aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/Kconfig13
-rw-r--r--drivers/scsi/Makefile3
-rw-r--r--drivers/scsi/cpqfcTS.h19
-rw-r--r--drivers/scsi/cpqfcTSchip.h238
-rw-r--r--drivers/scsi/cpqfcTScontrol.c2231
-rw-r--r--drivers/scsi/cpqfcTSi2c.c493
-rw-r--r--drivers/scsi/cpqfcTSinit.c2096
-rw-r--r--drivers/scsi/cpqfcTSioctl.h94
-rw-r--r--drivers/scsi/cpqfcTSstructs.h1530
-rw-r--r--drivers/scsi/cpqfcTStrigger.c33
-rw-r--r--drivers/scsi/cpqfcTStrigger.h8
-rw-r--r--drivers/scsi/cpqfcTSworker.c6516
12 files changed, 0 insertions, 13274 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 78c33180ebed..afeca325b4dc 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -620,19 +620,6 @@ config SCSI_OMIT_FLASHPOINT
620 substantial, so users of MultiMaster Host Adapters may wish to omit 620 substantial, so users of MultiMaster Host Adapters may wish to omit
621 it. 621 it.
622 622
623#
624# This is marked broken because it uses over 4kB of stack in
625# just two routines:
626# 2076 CpqTsProcessIMQEntry
627# 2052 PeekIMQEntry
628#
629config SCSI_CPQFCTS
630 tristate "Compaq Fibre Channel 64-bit/66Mhz HBA support"
631 depends on PCI && SCSI && BROKEN
632 help
633 Say Y here to compile in support for the Compaq StorageWorks Fibre
634 Channel 64-bit/66Mhz Host Bus Adapter.
635
636config SCSI_DMX3191D 623config SCSI_DMX3191D
637 tristate "DMX3191D SCSI support" 624 tristate "DMX3191D SCSI support"
638 depends on PCI && SCSI 625 depends on PCI && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 8dfb9884afe0..b88b8c455598 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -120,7 +120,6 @@ obj-$(CONFIG_JAZZ_ESP) += NCR53C9x.o jazz_esp.o
120obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o 120obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o
121obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o 121obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
122obj-$(CONFIG_SCSI_FCAL) += fcal.o 122obj-$(CONFIG_SCSI_FCAL) += fcal.o
123obj-$(CONFIG_SCSI_CPQFCTS) += cpqfc.o
124obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o 123obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o
125obj-$(CONFIG_SCSI_NSP32) += nsp32.o 124obj-$(CONFIG_SCSI_NSP32) += nsp32.o
126obj-$(CONFIG_SCSI_IPR) += ipr.o 125obj-$(CONFIG_SCSI_IPR) += ipr.o
@@ -165,8 +164,6 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
165CFLAGS_ncr53c8xx.o := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m) 164CFLAGS_ncr53c8xx.o := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m)
166zalon7xx-objs := zalon.o ncr53c8xx.o 165zalon7xx-objs := zalon.o ncr53c8xx.o
167NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o 166NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o
168cpqfc-objs := cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o \
169 cpqfcTSworker.o cpqfcTStrigger.o
170libata-objs := libata-core.o libata-scsi.o 167libata-objs := libata-core.o libata-scsi.o
171 168
172# Files generated that shall be removed upon make clean 169# Files generated that shall be removed upon make clean
diff --git a/drivers/scsi/cpqfcTS.h b/drivers/scsi/cpqfcTS.h
deleted file mode 100644
index 7ce53d88cb96..000000000000
--- a/drivers/scsi/cpqfcTS.h
+++ /dev/null
@@ -1,19 +0,0 @@
1#ifndef CPQFCTS_H
2#define CPQFCTS_H
3#include "cpqfcTSstructs.h"
4
5// These functions are required by the Linux SCSI layers
6extern int cpqfcTS_detect(Scsi_Host_Template *);
7extern int cpqfcTS_release(struct Scsi_Host *);
8extern const char * cpqfcTS_info(struct Scsi_Host *);
9extern int cpqfcTS_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
10extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
11extern int cpqfcTS_abort(Scsi_Cmnd *);
12extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int);
13extern int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd);
14extern int cpqfcTS_eh_device_reset(Scsi_Cmnd *);
15extern int cpqfcTS_biosparam(struct scsi_device *, struct block_device *,
16 sector_t, int[]);
17extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg);
18
19#endif /* CPQFCTS_H */
diff --git a/drivers/scsi/cpqfcTSchip.h b/drivers/scsi/cpqfcTSchip.h
deleted file mode 100644
index 14b83373861f..000000000000
--- a/drivers/scsi/cpqfcTSchip.h
+++ /dev/null
@@ -1,238 +0,0 @@
1/* Copyright(c) 2000, Compaq Computer Corporation
2 * Fibre Channel Host Bus Adapter
3 * 64-bit, 66MHz PCI
4 * Originally developed and tested on:
5 * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ...
6 * SP# P225CXCBFIEL6T, Rev XC
7 * SP# 161290-001, Rev XD
8 * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
13 * later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 * Written by Don Zimmerman
20*/
21#ifndef CPQFCTSCHIP_H
22#define CPQFCTSCHIP_H
23#ifndef TACHYON_CHIP_INC
24
25// FC-PH (Physical) specification levels for Login payloads
26// NOTE: These are NOT strictly complied with by any FC vendors
27
28#define FC_PH42 0x08
29#define FC_PH43 0x09
30#define FC_PH3 0x20
31
32#define TACHLITE_TS_RX_SIZE 1024 // max inbound frame size
33// "I" prefix is for Include
34
35#define IVENDID 0x00 // word
36#define IDEVID 0x02
37#define ITLCFGCMD 0x04
38#define IMEMBASE 0x18 // Tachyon
39#define ITLMEMBASE 0x1C // Tachlite
40#define IIOBASEL 0x10 // Tachyon I/O base address, lower 256 bytes
41#define IIOBASEU 0x14 // Tachyon I/O base address, upper 256 bytes
42#define ITLIOBASEL 0x14 // TachLite I/O base address, lower 256 bytes
43#define ITLIOBASEU 0x18 // TachLite I/O base address, upper 256 bytes
44#define ITLRAMBASE 0x20 // TL on-board RAM start
45#define ISROMBASE 0x24
46#define IROMBASE 0x30
47
48#define ICFGCMD 0x04 // PCI config - PCI config access (word)
49#define ICFGSTAT 0x06 // PCI status (R - word)
50#define IRCTR_WCTR 0x1F2 // ROM control / pre-fetch wait counter
51#define IPCIMCTR 0x1F3 // PCI master control register
52#define IINTPEND 0x1FD // Interrupt pending (I/O Upper - Tachyon & TL)
53#define IINTEN 0x1FE // Interrupt enable (I/O Upper - Tachyon & TL)
54#define IINTSTAT 0x1FF // Interrupt status (I/O Upper - Tachyon & TL)
55
56#define IMQ_BASE 0x80
57#define IMQ_LENGTH 0x84
58#define IMQ_CONSUMER_INDEX 0x88
59#define IMQ_PRODUCER_INDEX 0x8C // Tach copies its INDX to bits 0-7 of value
60
61/*
62// IOBASE UPPER
63#define SFSBQ_BASE 0x00 // single-frame sequences
64#define SFSBQ_LENGTH 0x04
65#define SFSBQ_PRODUCER_INDEX 0x08
66#define SFSBQ_CONSUMER_INDEX 0x0C // (R)
67#define SFS_BUFFER_LENGTH 0X10
68 // SCSI-FCP hardware assists
69#define SEST_BASE 0x40 // SSCI Exchange State Table
70#define SEST_LENGTH 0x44
71#define SCSI_BUFFER_LENGTH 0x48
72#define SEST_LINKED_LIST 0x4C
73
74#define TACHYON_My_ID 0x6C
75#define TACHYON_CONFIGURATION 0x84 // (R/W) reset val 2
76#define TACHYON_CONTROL 0x88
77#define TACHYON_STATUS 0x8C // (R)
78#define TACHYON_FLUSH_SEST 0x90 // (R/W)
79#define TACHYON_EE_CREDIT_TMR 0x94 // (R)
80#define TACHYON_BB_CREDIT_TMR 0x98 // (R)
81#define TACHYON_RCV_FRAME_ERR 0x9C // (R)
82#define FRAME_MANAGER_CONFIG 0xC0 // (R/W)
83#define FRAME_MANAGER_CONTROL 0xC4
84#define FRAME_MANAGER_STATUS 0xC8 // (R)
85#define FRAME_MANAGER_ED_TOV 0xCC
86#define FRAME_MANAGER_LINK_ERR1 0xD0 // (R)
87#define FRAME_MANAGER_LINK_ERR2 0xD4 // (R)
88#define FRAME_MANAGER_TIMEOUT2 0xD8 // (W)
89#define FRAME_MANAGER_BB_CREDIT 0xDC // (R)
90#define FRAME_MANAGER_WWN_HI 0xE0 // (R/W)
91#define FRAME_MANAGER_WWN_LO 0xE4 // (R/W)
92#define FRAME_MANAGER_RCV_AL_PA 0xE8 // (R)
93#define FRAME_MANAGER_PRIMITIVE 0xEC // {K28.5} byte1 byte2 byte3
94*/
95
96#define TL_MEM_ERQ_BASE 0x0 //ERQ Base
97#define TL_IO_ERQ_BASE 0x0 //ERQ base
98
99#define TL_MEM_ERQ_LENGTH 0x4 //ERQ Length
100#define TL_IO_ERQ_LENGTH 0x4 //ERQ Length
101
102#define TL_MEM_ERQ_PRODUCER_INDEX 0x8 //ERQ Producer Index register
103#define TL_IO_ERQ_PRODUCER_INDEX 0x8 //ERQ Producer Index register
104
105#define TL_MEM_ERQ_CONSUMER_INDEX_ADR 0xC //ERQ Consumer Index address register
106#define TL_IO_ERQ_CONSUMER_INDEX_ADR 0xC //ERQ Consumer Index address register
107
108#define TL_MEM_ERQ_CONSUMER_INDEX 0xC //ERQ Consumer Index
109#define TL_IO_ERQ_CONSUMER_INDEX 0xC //ERQ Consumer Index
110
111#define TL_MEM_SFQ_BASE 0x50 //SFQ Base
112#define TL_IO_SFQ_BASE 0x50 //SFQ base
113
114#define TL_MEM_SFQ_LENGTH 0x54 //SFQ Length
115#define TL_IO_SFQ_LENGTH 0x54 //SFQ Length
116
117#define TL_MEM_SFQ_CONSUMER_INDEX 0x58 //SFQ Consumer Index
118#define TL_IO_SFQ_CONSUMER_INDEX 0x58 //SFQ Consumer Index
119
120#define TL_MEM_IMQ_BASE 0x80 //IMQ Base
121#define TL_IO_IMQ_BASE 0x80 //IMQ base
122
123#define TL_MEM_IMQ_LENGTH 0x84 //IMQ Length
124#define TL_IO_IMQ_LENGTH 0x84 //IMQ Length
125
126#define TL_MEM_IMQ_CONSUMER_INDEX 0x88 //IMQ Consumer Index
127#define TL_IO_IMQ_CONSUMER_INDEX 0x88 //IMQ Consumer Index
128
129#define TL_MEM_IMQ_PRODUCER_INDEX_ADR 0x8C //IMQ Producer Index address register
130#define TL_IO_IMQ_PRODUCER_INDEX_ADR 0x8C //IMQ Producer Index address register
131
132#define TL_MEM_SEST_BASE 0x140 //SFQ Base
133#define TL_IO_SEST_BASE 0x40 //SFQ base
134
135#define TL_MEM_SEST_LENGTH 0x144 //SFQ Length
136#define TL_IO_SEST_LENGTH 0x44 //SFQ Length
137
138#define TL_MEM_SEST_LINKED_LIST 0x14C
139
140#define TL_MEM_SEST_SG_PAGE 0x168 // Extended Scatter/Gather page size
141
142#define TL_MEM_TACH_My_ID 0x16C
143#define TL_IO_TACH_My_ID 0x6C //My AL_PA ID
144
145#define TL_MEM_TACH_CONFIG 0x184 //Tachlite Configuration register
146#define TL_IO_CONFIG 0x84 //Tachlite Configuration register
147
148#define TL_MEM_TACH_CONTROL 0x188 //Tachlite Control register
149#define TL_IO_CTR 0x88 //Tachlite Control register
150
151#define TL_MEM_TACH_STATUS 0x18C //Tachlite Status register
152#define TL_IO_STAT 0x8C //Tachlite Status register
153
154#define TL_MEM_FM_CONFIG 0x1C0 //Frame Manager Configuration register
155#define TL_IO_FM_CONFIG 0xC0 //Frame Manager Configuration register
156
157#define TL_MEM_FM_CONTROL 0x1C4 //Frame Manager Control
158#define TL_IO_FM_CTL 0xC4 //Frame Manager Control
159
160#define TL_MEM_FM_STATUS 0x1C8 //Frame Manager Status
161#define TL_IO_FM_STAT 0xC8 //Frame Manager Status
162
163#define TL_MEM_FM_LINK_STAT1 0x1D0 //Frame Manager Link Status 1
164#define TL_IO_FM_LINK_STAT1 0xD0 //Frame Manager Link Status 1
165
166#define TL_MEM_FM_LINK_STAT2 0x1D4 //Frame Manager Link Status 2
167#define TL_IO_FM_LINK_STAT2 0xD4 //Frame Manager Link Status 2
168
169#define TL_MEM_FM_TIMEOUT2 0x1D8 // (W)
170
171#define TL_MEM_FM_BB_CREDIT0 0x1DC
172
173#define TL_MEM_FM_WWN_HI 0x1E0 //Frame Manager World Wide Name High
174#define TL_IO_FM_WWN_HI 0xE0 //Frame Manager World Wide Name High
175
176#define TL_MEM_FM_WWN_LO 0x1E4 //Frame Manager World Wide Name LOW
177#define TL_IO_FM_WWN_LO 0xE4 //Frame Manager World Wide Name Low
178
179#define TL_MEM_FM_RCV_AL_PA 0x1E8 //Frame Manager AL_PA Received register
180#define TL_IO_FM_ALPA 0xE8 //Frame Manager AL_PA Received register
181
182#define TL_MEM_FM_ED_TOV 0x1CC
183
184#define TL_IO_ROMCTR 0xFA //TL PCI ROM Control Register
185#define TL_IO_PCIMCTR 0xFB //TL PCI Master Control Register
186#define TL_IO_SOFTRST 0xFC //Tachlite Configuration register
187#define TL_MEM_SOFTRST 0x1FC //Tachlite Configuration register
188
189// completion message types (bit 8 set means Interrupt generated)
190// CM_Type
191#define OUTBOUND_COMPLETION 0
192#define ERROR_IDLE_COMPLETION 0x01
193#define OUT_HI_PRI_COMPLETION 0x01
194#define INBOUND_MFS_COMPLETION 0x02
195#define INBOUND_000_COMPLETION 0x03
196#define INBOUND_SFS_COMPLETION 0x04 // Tachyon & TachLite
197#define ERQ_FROZEN_COMPLETION 0x06 // TachLite
198#define INBOUND_C1_TIMEOUT 0x05
199#define INBOUND_BUSIED_FRAME 0x06
200#define SFS_BUF_WARN 0x07
201#define FCP_FROZEN_COMPLETION 0x07 // TachLite
202#define MFS_BUF_WARN 0x08
203#define IMQ_BUF_WARN 0x09
204#define FRAME_MGR_INTERRUPT 0x0A
205#define READ_STATUS 0x0B
206#define INBOUND_SCSI_DATA_COMPLETION 0x0C
207#define INBOUND_FCP_XCHG_COMPLETION 0x0C // TachLite
208#define INBOUND_SCSI_DATA_COMMAND 0x0D
209#define BAD_SCSI_FRAME 0x0E
210#define INB_SCSI_STATUS_COMPLETION 0x0F
211#define BUFFER_PROCESSED_COMPLETION 0x11
212
213// FC-AL (Tachyon) Loop Port State Machine defs
214// (loop "Up" states)
215#define MONITORING 0x0
216#define ARBITRATING 0x1
217#define ARBITRAT_WON 0x2
218#define OPEN 0x3
219#define OPENED 0x4
220#define XMITTD_CLOSE 0x5
221#define RCVD_CLOSE 0x6
222#define TRANSFER 0x7
223
224// (loop "Down" states)
225#define INITIALIZING 0x8
226#define O_I_INIT 0x9
227#define O_I_PROTOCOL 0xa
228#define O_I_LIP_RCVD 0xb
229#define HOST_CONTROL 0xc
230#define LOOP_FAIL 0xd
231// (no 0xe)
232#define OLD_PORT 0xf
233
234
235
236#define TACHYON_CHIP_INC
237#endif
238#endif /* CPQFCTSCHIP_H */
diff --git a/drivers/scsi/cpqfcTScontrol.c b/drivers/scsi/cpqfcTScontrol.c
deleted file mode 100644
index bd94c70f473d..000000000000
--- a/drivers/scsi/cpqfcTScontrol.c
+++ /dev/null
@@ -1,2231 +0,0 @@
1/* Copyright 2000, Compaq Computer Corporation
2 * Fibre Channel Host Bus Adapter
3 * 64-bit, 66MHz PCI
4 * Originally developed and tested on:
5 * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ...
6 * SP# P225CXCBFIEL6T, Rev XC
7 * SP# 161290-001, Rev XD
8 * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
13 * later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 * Written by Don Zimmerman
20*/
21/* These functions control the host bus adapter (HBA) hardware. The main chip
22 control takes place in the interrupt handler where we process the IMQ
23 (Inbound Message Queue). The IMQ is Tachyon's way of communicating FC link
24 events and state information to the driver. The Single Frame Queue (SFQ)
25 buffers incoming FC frames for processing by the driver. References to
26 "TL/TS UG" are for:
27 "HP HPFC-5100/5166 Tachyon TL/TS ICs User Guide", August 16, 1999, 1st Ed.
28 Hewlitt Packard Manual Part Number 5968-1083E.
29*/
30
31#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
32
33#include <linux/blkdev.h>
34#include <linux/kernel.h>
35#include <linux/string.h>
36#include <linux/ioport.h> // request_region() prototype
37#include <linux/sched.h>
38#include <linux/slab.h> // need "kfree" for ext. S/G pages
39#include <linux/types.h>
40#include <linux/pci.h>
41#include <linux/delay.h>
42#include <linux/unistd.h>
43#include <asm/io.h> // struct pt_regs for IRQ handler & Port I/O
44#include <asm/irq.h>
45#include <linux/spinlock.h>
46
47#include "scsi.h"
48#include <scsi/scsi_host.h> // Scsi_Host definition for INT handler
49#include "cpqfcTSchip.h"
50#include "cpqfcTSstructs.h"
51
52//#define IMQ_DEBUG 1
53
54static void fcParseLinkStatusCounters(TACHYON * fcChip);
55static void CpqTsGetSFQEntry(TACHYON * fcChip,
56 USHORT pi, ULONG * buffr, BOOLEAN UpdateChip);
57
58static void
59cpqfc_free_dma_consistent(CPQFCHBA *cpqfcHBAdata)
60{
61 // free up the primary EXCHANGES struct and Link Q
62 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
63
64 if (fcChip->Exchanges != NULL)
65 pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES),
66 fcChip->Exchanges, fcChip->exch_dma_handle);
67 fcChip->Exchanges = NULL;
68 if (cpqfcHBAdata->fcLQ != NULL)
69 pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE),
70 cpqfcHBAdata->fcLQ, cpqfcHBAdata->fcLQ_dma_handle);
71 cpqfcHBAdata->fcLQ = NULL;
72}
73
74// Note special requirements for Q alignment! (TL/TS UG pg. 190)
75// We place critical index pointers at end of QUE elements to assist
76// in non-symbolic (i.e. memory dump) debugging
77// opcode defines placement of Queues (e.g. local/external RAM)
78
79int CpqTsCreateTachLiteQues( void* pHBA, int opcode)
80{
81 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
82 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
83
84 int iStatus=0;
85 unsigned long ulAddr;
86 dma_addr_t ERQdma, IMQdma, SPQdma, SESTdma;
87 int i;
88
89 // NOTE! fcMemManager() will return system virtual addresses.
90 // System (kernel) virtual addresses, though non-paged, still
91 // aren't physical addresses. Convert to PHYSICAL_ADDRESS for Tachyon's
92 // DMA use.
93 ENTER("CreateTachLiteQues");
94
95
96 // Allocate primary EXCHANGES array...
97 fcChip->Exchanges = NULL;
98 cpqfcHBAdata->fcLQ = NULL;
99
100 /* printk("Allocating %u for %u Exchanges ",
101 (ULONG)sizeof(FC_EXCHANGES), TACH_MAX_XID); */
102 fcChip->Exchanges = pci_alloc_consistent(cpqfcHBAdata->PciDev,
103 sizeof(FC_EXCHANGES), &fcChip->exch_dma_handle);
104 /* printk("@ %p\n", fcChip->Exchanges); */
105
106 if( fcChip->Exchanges == NULL ) // fatal error!!
107 {
108 printk("pci_alloc_consistent failure on Exchanges: fatal error\n");
109 return -1;
110 }
111 // zero out the entire EXCHANGE space
112 memset( fcChip->Exchanges, 0, sizeof( FC_EXCHANGES));
113
114
115 /* printk("Allocating %u for LinkQ ", (ULONG)sizeof(FC_LINK_QUE)); */
116 cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev,
117 sizeof( FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle);
118 /* printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH); */
119
120 if( cpqfcHBAdata->fcLQ == NULL ) // fatal error!!
121 {
122 cpqfc_free_dma_consistent(cpqfcHBAdata);
123 printk("pci_alloc_consistent() failure on fc Link Que: fatal error\n");
124 return -1;
125 }
126 // zero out the entire EXCHANGE space
127 memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));
128
129 // Verify that basic Tach I/O registers are not NULL
130 if( !fcChip->Registers.ReMapMemBase )
131 {
132 cpqfc_free_dma_consistent(cpqfcHBAdata);
133 printk("HBA base address NULL: fatal error\n");
134 return -1;
135 }
136
137
138 // Initialize the fcMemManager memory pairs (stores allocated/aligned
139 // pairs for future freeing)
140 memset( cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem));
141
142
143 // Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes)
144
145 fcChip->ERQ = fcMemManager( cpqfcHBAdata->PciDev,
146 &cpqfcHBAdata->dynamic_mem[0],
147 sizeof( TachLiteERQ ), 32*(ERQ_LEN), 0L, &ERQdma);
148 if( !fcChip->ERQ )
149 {
150 cpqfc_free_dma_consistent(cpqfcHBAdata);
151 printk("pci_alloc_consistent/alignment failure on ERQ: fatal error\n");
152 return -1;
153 }
154 fcChip->ERQ->length = ERQ_LEN-1;
155 ulAddr = (ULONG) ERQdma;
156#if BITS_PER_LONG > 32
157 if( (ulAddr >> 32) )
158 {
159 cpqfc_free_dma_consistent(cpqfcHBAdata);
160 printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n",
161 (void*)ulAddr);
162 return -1; // failed
163 }
164#endif
165 fcChip->ERQ->base = (ULONG)ulAddr; // copy for quick reference
166
167
168 // Allocate Tach's Inbound Message Queue (32 bytes per entry)
169
170 fcChip->IMQ = fcMemManager( cpqfcHBAdata->PciDev,
171 &cpqfcHBAdata->dynamic_mem[0],
172 sizeof( TachyonIMQ ), 32*(IMQ_LEN), 0L, &IMQdma );
173 if( !fcChip->IMQ )
174 {
175 cpqfc_free_dma_consistent(cpqfcHBAdata);
176 printk("pci_alloc_consistent/alignment failure on IMQ: fatal error\n");
177 return -1;
178 }
179 fcChip->IMQ->length = IMQ_LEN-1;
180
181 ulAddr = IMQdma;
182#if BITS_PER_LONG > 32
183 if( (ulAddr >> 32) )
184 {
185 cpqfc_free_dma_consistent(cpqfcHBAdata);
186 printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
187 (void*)ulAddr);
188 return -1; // failed
189 }
190#endif
191 fcChip->IMQ->base = (ULONG)ulAddr; // copy for quick reference
192
193
194 // Allocate Tach's Single Frame Queue (64 bytes per entry)
195 fcChip->SFQ = fcMemManager( cpqfcHBAdata->PciDev,
196 &cpqfcHBAdata->dynamic_mem[0],
197 sizeof( TachLiteSFQ ), 64*(SFQ_LEN),0L, &SPQdma );
198 if( !fcChip->SFQ )
199 {
200 cpqfc_free_dma_consistent(cpqfcHBAdata);
201 printk("pci_alloc_consistent/alignment failure on SFQ: fatal error\n");
202 return -1;
203 }
204 fcChip->SFQ->length = SFQ_LEN-1; // i.e. Que length [# entries -
205 // min. 32; max. 4096 (0xffff)]
206
207 ulAddr = SPQdma;
208#if BITS_PER_LONG > 32
209 if( (ulAddr >> 32) )
210 {
211 cpqfc_free_dma_consistent(cpqfcHBAdata);
212 printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
213 (void*)ulAddr);
214 return -1; // failed
215 }
216#endif
217 fcChip->SFQ->base = (ULONG)ulAddr; // copy for quick reference
218
219
220 // Allocate SCSI Exchange State Table; aligned nearest @sizeof
221 // power-of-2 boundary
222 // LIVE DANGEROUSLY! Assume the boundary for SEST mem will
223 // be on physical page (e.g. 4k) boundary.
224 /* printk("Allocating %u for TachSEST for %u Exchanges\n",
225 (ULONG)sizeof(TachSEST), TACH_SEST_LEN); */
226 fcChip->SEST = fcMemManager( cpqfcHBAdata->PciDev,
227 &cpqfcHBAdata->dynamic_mem[0],
228 sizeof(TachSEST), 4, 0L, &SESTdma );
229// sizeof(TachSEST), 64*TACH_SEST_LEN, 0L );
230 if( !fcChip->SEST )
231 {
232 cpqfc_free_dma_consistent(cpqfcHBAdata);
233 printk("pci_alloc_consistent/alignment failure on SEST: fatal error\n");
234 return -1;
235 }
236
237 for( i=0; i < TACH_SEST_LEN; i++) // for each exchange
238 fcChip->SEST->sgPages[i] = NULL;
239
240 fcChip->SEST->length = TACH_SEST_LEN; // e.g. DON'T subtract one
241 // (TL/TS UG, pg 153)
242
243 ulAddr = SESTdma;
244#if BITS_PER_LONG > 32
245 if( (ulAddr >> 32) )
246 {
247 cpqfc_free_dma_consistent(cpqfcHBAdata);
248 printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
249 (void*)ulAddr);
250 return -1; // failed
251 }
252#endif
253 fcChip->SEST->base = (ULONG)ulAddr; // copy for quick reference
254
255
256 // Now that structures are defined,
257 // fill in Tachyon chip registers...
258
259 // EEEEEEEE EXCHANGE REQUEST QUEUE
260
261 writel( fcChip->ERQ->base,
262 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
263
264 writel( fcChip->ERQ->length,
265 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH));
266
267
268 fcChip->ERQ->producerIndex = 0L;
269 writel( fcChip->ERQ->producerIndex,
270 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX));
271
272
273 // NOTE! write consumer index last, since the write
274 // causes Tachyon to process the other registers
275
276 ulAddr = ((unsigned long)&fcChip->ERQ->consumerIndex -
277 (unsigned long)fcChip->ERQ) + (unsigned long) ERQdma;
278
279 // NOTE! Tachyon DMAs to the ERQ consumer Index host
280 // address; must be correctly aligned
281 writel( (ULONG)ulAddr,
282 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR));
283
284
285
286 // IIIIIIIIIIIII INBOUND MESSAGE QUEUE
287 // Tell Tachyon where the Que starts
288
289 // set the Host's pointer for Tachyon to access
290
291 /* printk(" cpqfcTS: writing IMQ BASE %Xh ", fcChip->IMQ->base ); */
292 writel( fcChip->IMQ->base,
293 (fcChip->Registers.ReMapMemBase + IMQ_BASE));
294
295 writel( fcChip->IMQ->length,
296 (fcChip->Registers.ReMapMemBase + IMQ_LENGTH));
297
298 writel( fcChip->IMQ->consumerIndex,
299 (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
300
301
302 // NOTE: TachLite DMAs to the producerIndex host address
303 // must be correctly aligned with address bits 1-0 cleared
304 // Writing the BASE register clears the PI register, so write it last
305 ulAddr = ((unsigned long)&fcChip->IMQ->producerIndex -
306 (unsigned long)fcChip->IMQ) + (unsigned long) IMQdma;
307
308#if BITS_PER_LONG > 32
309 if( (ulAddr >> 32) )
310 {
311 cpqfc_free_dma_consistent(cpqfcHBAdata);
312 printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
313 (void*)ulAddr);
314 return -1; // failed
315 }
316#endif
317#if DBG
318 printk(" PI %Xh\n", (ULONG)ulAddr );
319#endif
320 writel( (ULONG)ulAddr,
321 (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX));
322
323
324
325 // SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE
326 // Tell TachLite where the Que starts
327
328 writel( fcChip->SFQ->base,
329 (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE));
330
331 writel( fcChip->SFQ->length,
332 (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH));
333
334
335 // tell TachLite where SEST table is & how long
336 writel( fcChip->SEST->base,
337 (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE));
338
339 /* printk(" cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n",
340 fcChip->SEST, fcChip->SEST->base,
341 fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE); */
342
343 writel( fcChip->SEST->length,
344 (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH));
345
346 writel( (TL_EXT_SG_PAGE_COUNT-1),
347 (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE));
348
349
350 LEAVE("CreateTachLiteQues");
351
352 return iStatus;
353}
354
355
356
357// function to return TachLite to Power On state
358// 1st - reset tachyon ('SOFT' reset)
359// others - future
360
361int CpqTsResetTachLite(void *pHBA, int type)
362{
363 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
364 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
365 ULONG ulBuff, i;
366 int ret_status=0; // def. success
367
368 ENTER("ResetTach");
369
370 switch(type)
371 {
372
373 case CLEAR_FCPORTS:
374
375 // in case he was running previously, mask Tach's interrupt
376 writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
377
378 // de-allocate mem for any Logged in ports
379 // (e.g., our module is unloading)
380 // search the forward linked list, de-allocating
381 // the memory we allocated when the port was initially logged in
382 {
383 PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort;
384 PFC_LOGGEDIN_PORT ptr;
385// printk("checking for allocated LoggedInPorts...\n");
386
387 while( pLoggedInPort )
388 {
389 ptr = pLoggedInPort;
390 pLoggedInPort = ptr->pNextPort;
391// printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n",
392// ptr, ptr->port_id);
393 kfree( ptr );
394 }
395 }
396 // (continue resetting hardware...)
397
398 case 1: // RESTART Tachyon (power-up state)
399
400 // in case he was running previously, mask Tach's interrupt
401 writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
402 // turn OFF laser (NOTE: laser is turned
403 // off during reset, because GPIO4 is cleared
404 // to 0 by reset action - see TLUM, sec 7.22)
405 // However, CPQ 64-bit HBAs have a "health
406 // circuit" which keeps laser ON for a brief
407 // period after it is turned off ( < 1s)
408
409 fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 0);
410
411
412
413 // soft reset timing constraints require:
414 // 1. set RST to 1
415 // 2. read SOFTRST register
416 // (128 times per R. Callison code)
417 // 3. clear PCI ints
418 // 4. clear RST to 0
419 writel( 0xff000001L,
420 (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
421
422 for( i=0; i<128; i++)
423 ulBuff = readl( fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST);
424
425 // clear the soft reset
426 for( i=0; i<8; i++)
427 writel( 0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
428
429
430
431 // clear out our copy of Tach regs,
432 // because they must be invalid now,
433 // since TachLite reset all his regs.
434 CpqTsDestroyTachLiteQues(cpqfcHBAdata,0); // remove Host-based Que structs
435 cpqfcTSClearLinkStatusCounters(fcChip); // clear our s/w accumulators
436 // lower bits give GBIC info
437 fcChip->Registers.TYstatus.value =
438 readl( fcChip->Registers.TYstatus.address );
439 break;
440
441/*
442 case 2: // freeze SCSI
443 case 3: // reset Outbound command que (ERQ)
444 case 4: // unfreeze OSM (Outbound Seq. Man.) 'er'
445 case 5: // report status
446
447 break;
448*/
449 default:
450 ret_status = -1; // invalid option passed to RESET function
451 break;
452 }
453 LEAVE("ResetTach");
454 return ret_status;
455}
456
457
458
459
460
461
462// 'addrBase' is IOBaseU for both TachLite and (older) Tachyon
463int CpqTsLaserControl( void* addrBase, int opcode )
464{
465 ULONG dwBuff;
466
467 dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL) ); // read TL Control reg
468 // (change only bit 4)
469 if( opcode == 1)
470 dwBuff |= ~0xffffffefL; // set - ON
471 else
472 dwBuff &= 0xffffffefL; // clear - OFF
473 writel( dwBuff, (addrBase + TL_MEM_TACH_CONTROL)); // write TL Control reg
474 return 0;
475}
476
477
478
479
480
481// Use controller's "Options" field to determine loopback mode (if any)
482// internal loopback (silicon - no GBIC)
483// external loopback (GBIC - no FC loop)
484// no loopback: L_PORT, external cable from GBIC required
485
486int CpqTsInitializeFrameManager( void *pChip, int opcode)
487{
488 PTACHYON fcChip;
489 int iStatus;
490 ULONG wwnLo, wwnHi; // for readback verification
491
492 ENTER("InitializeFrameManager");
493 fcChip = (PTACHYON)pChip;
494 if( !fcChip->Registers.ReMapMemBase ) // undefined controller?
495 return -1;
496
497 // TL/TS UG, pg. 184
498 // 0x0065 = 100ms for RT_TOV
499 // 0x01f5 = 500ms for ED_TOV
500 // 0x07D1 = 2000ms
501 fcChip->Registers.ed_tov.value = 0x006507D1;
502 writel( fcChip->Registers.ed_tov.value,
503 (fcChip->Registers.ed_tov.address));
504
505
506 // Set LP_TOV to the FC-AL2 specified 2 secs.
507 // TL/TS UG, pg. 185
508 writel( 0x07d00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
509
510
511 // Now try to read the WWN from the adapter's NVRAM
512 iStatus = CpqTsReadWriteWWN( fcChip, 1); // '1' for READ
513
514 if( iStatus ) // NVRAM read failed?
515 {
516 printk(" WARNING! HBA NVRAM WWN read failed - make alias\n");
517 // make up a WWN. If NULL or duplicated on loop, FC loop may hang!
518
519
520 fcChip->Registers.wwn_hi = (__u32)jiffies;
521 fcChip->Registers.wwn_hi |= 0x50000000L;
522 fcChip->Registers.wwn_lo = 0x44556677L;
523 }
524
525
526 writel( fcChip->Registers.wwn_hi,
527 fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
528
529 writel( fcChip->Registers.wwn_lo,
530 fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
531
532
533 // readback for verification:
534 wwnHi = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI );
535
536 wwnLo = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
537 // test for correct chip register WRITE/READ
538 DEBUG_PCI( printk(" WWN %08X%08X\n",
539 fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo ) );
540
541 if( wwnHi != fcChip->Registers.wwn_hi ||
542 wwnLo != fcChip->Registers.wwn_lo )
543 {
544 printk( "cpqfcTS: WorldWideName register load failed\n");
545 return -1; // FAILED!
546 }
547
548
549
550 // set Frame Manager Initialize command
551 fcChip->Registers.FMcontrol.value = 0x06;
552
553 // Note: for test/debug purposes, we may use "Hard" address,
554 // but we completely support "soft" addressing, including
555 // dynamically changing our address.
556 if( fcChip->Options.intLoopback == 1 ) // internal loopback
557 fcChip->Registers.FMconfig.value = 0x0f002080L;
558 else if( fcChip->Options.extLoopback == 1 ) // internal loopback
559 fcChip->Registers.FMconfig.value = 0x0f004080L;
560 else // L_Port
561 fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
562// fcChip->Registers.FMconfig.value = 0x01000080L; // soft address (can't pick)
563// fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
564
565 // write config to FM
566
567 if( !fcChip->Options.intLoopback && !fcChip->Options.extLoopback )
568 // (also need LASER for real LOOP)
569 fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 1); // turn on LASER
570
571 writel( fcChip->Registers.FMconfig.value,
572 fcChip->Registers.FMconfig.address);
573
574
575 // issue INITIALIZE command to FM - ACTION!
576 writel( fcChip->Registers.FMcontrol.value,
577 fcChip->Registers.FMcontrol.address);
578
579 LEAVE("InitializeFrameManager");
580
581 return 0;
582}
583
584
585
586
587
588// This "look ahead" function examines the IMQ for occurrence of
589// "type". Returns 1 if found, 0 if not.
590static int PeekIMQEntry( PTACHYON fcChip, ULONG type)
591{
592 ULONG CI = fcChip->IMQ->consumerIndex;
593 ULONG PI = fcChip->IMQ->producerIndex; // snapshot of IMQ indexes
594
595 while( CI != PI )
596 { // proceed with search
597 if( (++CI) >= IMQ_LEN ) CI = 0; // rollover check
598
599 switch( type )
600 {
601 case ELS_LILP_FRAME:
602 {
603 // first, we need to find an Inbound Completion message,
604 // If we find it, check the incoming frame payload (1st word)
605 // for LILP frame
606 if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104 )
607 {
608 TachFCHDR_GCMND* fchs;
609#error This is too much stack
610 ULONG ulFibreFrame[2048/4]; // max DWORDS in incoming FC Frame
611 USHORT SFQpi = (USHORT)(fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL);
612
613 CpqTsGetSFQEntry( fcChip,
614 SFQpi, // SFQ producer ndx
615 ulFibreFrame, // contiguous dest. buffer
616 FALSE); // DON'T update chip--this is a "lookahead"
617
618 fchs = (TachFCHDR_GCMND*)&ulFibreFrame;
619 if( fchs->pl[0] == ELS_LILP_FRAME)
620 {
621 return 1; // found the LILP frame!
622 }
623 else
624 {
625 // keep looking...
626 }
627 }
628 }
629 break;
630
631 case OUTBOUND_COMPLETION:
632 if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00 )
633 {
634
635 // any OCM errors?
636 if( fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L )
637 return 1; // found OCM error
638 }
639 break;
640
641
642
643 default:
644 break;
645 }
646 }
647 return 0; // failed to find "type"
648}
649
650
651static void SetTachTOV( CPQFCHBA* cpqfcHBAdata)
652{
653 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
654
655 // TL/TS UG, pg. 184
656 // 0x0065 = 100ms for RT_TOV
657 // 0x01f5 = 500ms for ED_TOV
658 // 0x07d1 = 2000ms for ED_TOV
659
660 // SANMark Level 1 requires an "initialization backoff"
661 // (See "SANMark Test Suite Level 1":
662 // initialization_timeout.fcal.SANMark-1.fc)
663 // We have to use 2sec, 24sec, then 128sec when login/
664 // port discovery processes fail to complete.
665
666 // when port discovery completes (logins done), we set
667 // ED_TOV to 500ms -- this is the normal operational case
668 // On the first Link Down, we'll move to 2 secs (7D1 ms)
669 if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x1f5)
670 fcChip->Registers.ed_tov.value = 0x006507D1;
671
672 // If we get another LST after we moved TOV to 2 sec,
673 // increase to 24 seconds (5DC1 ms) per SANMark!
674 else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x7D1)
675 fcChip->Registers.ed_tov.value = 0x00655DC1;
676
677 // If we get still another LST, set the max TOV (Tachyon
678 // has only 16 bits for ms timer, so the max is 65.5 sec)
679 else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x5DC1)
680 fcChip->Registers.ed_tov.value = 0x0065FFFF;
681
682 writel( fcChip->Registers.ed_tov.value,
683 (fcChip->Registers.ed_tov.address));
684 // keep the same 2sec LP_TOV
685 writel( 0x07D00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
686}
687
688
689// The IMQ is an array with IMQ_LEN length, each element (QEntry)
690// with eight 32-bit words. Tachyon PRODUCES a QEntry with each
691// message it wants to send to the host. The host CONSUMES IMQ entries
692
693// This function copies the current
694// (or oldest not-yet-processed) QEntry to
695// the caller, clears/ re-enables the interrupt, and updates the
696// (Host) Consumer Index.
697// Return value:
698// 0 message processed, none remain (producer and consumer
699// indexes match)
700// 1 message processed, more messages remain
701// -1 no message processed - none were available to process
702// Remarks:
703// TL/TS UG specifices that the following actions for
704// INTA_L handling:
705// 1. read PCI Interrupt Status register (0xff)
706// 2. all IMQ messages should be processed before writing the
707// IMQ consumer index.
708
709
710int CpqTsProcessIMQEntry(void *host)
711{
712 struct Scsi_Host *HostAdapter = (struct Scsi_Host *)host;
713 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
714 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
715 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
716 int iStatus;
717 USHORT i, RPCset, DPCset;
718 ULONG x_ID;
719 ULONG ulBuff, dwStatus;
720 TachFCHDR_GCMND* fchs;
721#error This is too much stack
722 ULONG ulFibreFrame[2048/4]; // max number of DWORDS in incoming Fibre Frame
723 UCHAR ucInboundMessageType; // Inbound CM, dword 3 "type" field
724
725 ENTER("ProcessIMQEntry");
726
727
728 // check TachLite's IMQ producer index -
729 // is a new message waiting for us?
730 // equal indexes means empty que
731
732 if( fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex )
733 { // need to process message
734
735
736#ifdef IMQ_DEBUG
737 printk("PI %X, CI %X type: %X\n",
738 fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex,
739 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);
740#endif
741 // Examine Completion Messages in IMQ
742 // what CM_Type?
743 switch( (UCHAR)(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type
744 & 0xffL) )
745 {
746 case OUTBOUND_COMPLETION:
747
748 // Remarks:
749 // x_IDs (OX_ID, RX_ID) are partitioned by SEST entries
750 // (starting at 0), and SFS entries (starting at
751 // SEST_LEN -- outside the SEST space).
752 // Psuedo code:
753 // x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index
754 // range check - x_ID
755 // if x_ID outside 'Transactions' length, error - exit
756 // if any OCM error, copy error status to Exchange slot
757 // if FCP ASSIST transaction (x_ID within SEST),
758 // call fcComplete (to App)
759 // ...
760
761
762 ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1];
763 x_ID = ulBuff & 0x7fffL; // lower 14 bits SEST_Index/Trans_ID
764 // Range check CM OX/RX_ID value...
765 if( x_ID < TACH_MAX_XID ) // don't go beyond array space
766 {
767
768
769 if( ulBuff & 0x20000000L ) // RPC -Response Phase Complete?
770 RPCset = 1; // (SEST transactions only)
771 else
772 RPCset = 0;
773
774 if( ulBuff & 0x40000000L ) // DPC -Data Phase Complete?
775 DPCset = 1; // (SEST transactions only)
776 else
777 DPCset = 0;
778 // set the status for this Outbound transaction's ID
779 dwStatus = 0L;
780 if( ulBuff & 0x10000000L ) // SPE? (SEST Programming Error)
781 dwStatus |= SESTPROG_ERR;
782
783 ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2];
784 if( ulBuff & 0x7a000000L ) // any other errs?
785 {
786 if( ulBuff & 0x40000000L )
787 dwStatus |= INV_ENTRY;
788 if( ulBuff & 0x20000000L )
789 dwStatus |= FRAME_TO; // FTO
790 if( ulBuff & 0x10000000L )
791 dwStatus |= HOSTPROG_ERR;
792 if( ulBuff & 0x08000000L )
793 dwStatus |= LINKFAIL_TX;
794 if( ulBuff & 0x02000000L )
795 dwStatus |= ABORTSEQ_NOTIFY; // ASN
796 }
797
798
799 if( dwStatus ) // any errors?
800 {
801 // set the Outbound Completion status
802 Exchanges->fcExchange[ x_ID ].status |= dwStatus;
803
804 // if this Outbound frame was for a SEST entry, automatically
805 // reque it in the case of LINKFAIL (it will restart on PDISC)
806 if( x_ID < TACH_SEST_LEN )
807 {
808
809 printk(" #OCM error %Xh x_ID %X# ",
810 dwStatus, x_ID);
811
812 Exchanges->fcExchange[x_ID].timeOut = 30000; // seconds default
813
814
815 // We Q ABTS for each exchange.
816 // NOTE: We can get FRAME_TO on bad alpa (device gone). Since
817 // bad alpa is reported before FRAME_TO, examine the status
818 // flags to see if the device is removed. If so, DON'T
819 // post an ABTS, since it will be terminated by the bad alpa
820 // message.
821 if( dwStatus & FRAME_TO ) // check for device removed...
822 {
823 if( !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) )
824 {
825 // presumes device is still there: send ABTS.
826
827 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
828 }
829 }
830 else // Abort all other errors
831 {
832 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
833 }
834
835 // if the HPE bit is set, we have to CLose the LOOP
836 // (see TL/TS UG, pg. 239)
837
838 if( dwStatus &= HOSTPROG_ERR )
839 // set CL bit (see TL/TS UG, pg. 172)
840 writel( 4, fcChip->Registers.FMcontrol.address);
841 }
842 }
843 // NOTE: we don't necessarily care about ALL completion messages...
844 // SCSI resp. complete OR
845 if( ((x_ID < TACH_SEST_LEN) && RPCset)||
846 (x_ID >= TACH_SEST_LEN) ) // non-SCSI command
847 {
848 // exchange done; complete to upper levels with status
849 // (if necessary) and free the exchange slot
850
851
852 if( x_ID >= TACH_SEST_LEN ) // Link Service Outbound frame?
853 // A Request or Reply has been sent
854 { // signal waiting WorkerThread
855
856 up( cpqfcHBAdata->TYOBcomplete); // frame is OUT of Tach
857
858 // WorkerThread will complete Xchng
859 }
860 else // X_ID is for FCP assist (SEST)
861 {
862 // TBD (target mode)
863// fcCompleteExchange( fcChip, x_ID); // TRE completed
864 }
865 }
866 }
867 else // ERROR CONDITION! bogus x_ID in completion message
868 {
869
870 printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID);
871
872 }
873
874
875
876 // Load the Frame Manager's error counters. We check them here
877 // because presumably the link is up and healthy enough for the
878 // counters to be meaningful (i.e., don't check them while loop
879 // is initializing).
880 fcChip->Registers.FMLinkStatus1.value = // get TL's counter
881 readl(fcChip->Registers.FMLinkStatus1.address);
882
883 fcChip->Registers.FMLinkStatus2.value = // get TL's counter
884 readl(fcChip->Registers.FMLinkStatus2.address);
885
886
887 fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
888 break;
889
890
891
892 case ERROR_IDLE_COMPLETION: // TachLite Error Idle...
893
894 // We usually get this when the link goes down during heavy traffic.
895 // For now, presume that if SEST Exchanges are open, we will
896 // get this as our cue to INVALIDATE all SEST entries
897 // (and we OWN all the SEST entries).
898 // See TL/TS UG, pg. 53
899
900 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
901 {
902
903 // Does this VALid SEST entry need to be invalidated for Abort?
904 fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
905 }
906
907 CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachyon, if Link OK
908
909 break;
910
911
912 case INBOUND_SFS_COMPLETION: //0x04
913 // NOTE! we must process this SFQ message to avoid SFQ filling
914 // up and stopping TachLite. Incoming commands are placed here,
915 // as well as 'unknown' frames (e.g. LIP loop position data)
916 // write this CM's producer index to global...
917 // TL/TS UG, pg 234:
918 // Type: 0 - reserved
919 // 1 - Unassisted FCP
920 // 2 - BAD FCP
921 // 3 - Unkown Frame
922 // 4-F reserved
923
924
925 fcChip->SFQ->producerIndex = (USHORT)
926 (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL);
927
928
929 ucInboundMessageType = 0; // default to useless frame
930
931 // we can only process two Types: 1, Unassisted FCP, and 3, Unknown
932 // Also, we aren't interested in processing frame fragments
933 // so don't Que anything with 'LKF' bit set
934 if( !(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2]
935 & 0x40000000) ) // 'LKF' link failure bit clear?
936 {
937 ucInboundMessageType = (UCHAR) // ICM DWord3, "Type"
938 (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL);
939 }
940 else
941 {
942 fcChip->fcStats.linkFailRX++;
943// printk("LKF (link failure) bit set on inbound message\n");
944 }
945
946 // clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff
947 CpqTsGetSFQEntry(
948 fcChip, // i.e. this Device Object
949 (USHORT)fcChip->SFQ->producerIndex, // SFQ producer ndx
950 ulFibreFrame, TRUE); // contiguous destination buffer, update chip
951
952 // analyze the incoming frame outside the INT handler...
953 // (i.e., Worker)
954
955 if( ucInboundMessageType == 1 )
956 {
957 fchs = (TachFCHDR_GCMND*)ulFibreFrame; // cast to examine IB frame
958 // don't fill up our Q with garbage - only accept FCP-CMND
959 // or XRDY frames
960 if( (fchs->d_id & 0xFF000000) == 0x06000000 ) // CMND
961 {
962 // someone sent us a SCSI command
963
964// fcPutScsiQue( cpqfcHBAdata,
965// SFQ_UNASSISTED_FCP, ulFibreFrame);
966 }
967 else if( ((fchs->d_id & 0xFF000000) == 0x07000000) || // RSP (status)
968 (fchs->d_id & 0xFF000000) == 0x05000000 ) // XRDY
969 {
970 ULONG x_ID;
971 // Unfortunately, ABTS requires a Freeze on the chip so
972 // we can modify the shared memory SEST. When frozen,
973 // any received Exchange frames cannot be processed by
974 // Tachyon, so they will be dumped in here. It is too
975 // complex to attempt the reconstruct these frames in
976 // the correct Exchange context, so we simply seek to
977 // find status or transfer ready frames, and cause the
978 // exchange to complete with errors before the timeout
979 // expires. We use a Linux Scsi Cmnd result code that
980 // causes immediate retry.
981
982
983 // Do we have an open exchange that matches this s_id
984 // and ox_id?
985 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
986 {
987 if( (fchs->s_id & 0xFFFFFF) ==
988 (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF)
989 &&
990 (fchs->ox_rx_id & 0xFFFF0000) ==
991 (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000) )
992 {
993 // printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id );
994 // simulate the anticipated error - since the
995 // SEST was frozen, frames were lost...
996 Exchanges->fcExchange[ x_ID ].status |= SFQ_FRAME;
997
998 // presumes device is still there: send ABTS.
999 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
1000 break; // done
1001 }
1002 }
1003 }
1004
1005 }
1006
1007 else if( ucInboundMessageType == 3)
1008 {
1009 // FC Link Service frames (e.g. PLOGI, ACC) come in here.
1010 cpqfcTSPutLinkQue( cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame);
1011
1012 }
1013
1014 else if( ucInboundMessageType == 2 ) // "bad FCP"?
1015 {
1016#ifdef IMQ_DEBUG
1017 printk("Bad FCP incoming frame discarded\n");
1018#endif
1019 }
1020
1021 else // don't know this type
1022 {
1023#ifdef IMQ_DEBUG
1024 printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);
1025#endif
1026 }
1027
1028 // Check the Frame Manager's error counters. We check them here
1029 // because presumably the link is up and healthy enough for the
1030 // counters to be meaningful (i.e., don't check them while loop
1031 // is initializing).
1032 fcChip->Registers.FMLinkStatus1.value = // get TL's counter
1033 readl(fcChip->Registers.FMLinkStatus1.address);
1034
1035
1036 fcChip->Registers.FMLinkStatus2.value = // get TL's counter
1037 readl(fcChip->Registers.FMLinkStatus2.address);
1038
1039
1040 break;
1041
1042
1043
1044
1045 // We get this CM because we issued a freeze
1046 // command to stop outbound frames. We issue the
1047 // freeze command at Link Up time; when this message
1048 // is received, the ERQ base can be switched and PDISC
1049 // frames can be sent.
1050
1051
1052 case ERQ_FROZEN_COMPLETION: // note: expect ERQ followed immediately
1053 // by FCP when freezing TL
1054 fcChip->Registers.TYstatus.value = // read what's frozen
1055 readl(fcChip->Registers.TYstatus.address);
1056 // (do nothing; wait for FCP frozen message)
1057 break;
1058 case FCP_FROZEN_COMPLETION:
1059
1060 fcChip->Registers.TYstatus.value = // read what's frozen
1061 readl(fcChip->Registers.TYstatus.address);
1062
1063 // Signal the kernel thread to proceed with SEST modification
1064 up( cpqfcHBAdata->TachFrozen);
1065
1066 break;
1067
1068
1069
1070 case INBOUND_C1_TIMEOUT:
1071 case MFS_BUF_WARN:
1072 case IMQ_BUF_WARN:
1073 break;
1074
1075
1076
1077
1078
1079 // In older Tachyons, we 'clear' the internal 'core' interrupt state
1080 // by reading the FMstatus register. In newer TachLite (Tachyon),
1081 // we must WRITE the register
1082 // to clear the condition (TL/TS UG, pg 179)
1083 case FRAME_MGR_INTERRUPT:
1084 {
1085 PFC_LOGGEDIN_PORT pLoggedInPort;
1086
1087 fcChip->Registers.FMstatus.value =
1088 readl( fcChip->Registers.FMstatus.address );
1089
1090 // PROBLEM: It is possible, especially with "dumb" hubs that
1091 // don't automatically LIP on by-pass of ports that are going
1092 // away, for the hub by-pass process to destroy critical
1093 // ordered sets of a frame. The result of this is a hung LPSM
1094 // (Loop Port State Machine), which on Tachyon results in a
1095 // (default 2 sec) Loop State Timeout (LST) FM message. We
1096 // want to avoid this relatively huge timeout by detecting
1097 // likely scenarios which will result in LST.
1098 // To do this, we could examine FMstatus for Loss of Synchronization
1099 // and/or Elastic Store (ES) errors. Of these, Elastic Store is better
1100 // because we get this indication more quickly than the LOS.
1101 // Not all ES errors are harmfull, so we don't want to LIP on every
1102 // ES. Instead, on every ES, detect whether our LPSM in in one
1103 // of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE,
1104 // or RECEIVED CLOSE. (See TL/TS UG, pg. 181)
1105 // If any of these LPSM states are detected
1106 // in combination with the LIP while LDn is not set,
1107 // send an FM init (LIP F7,F7 for loops)!
1108 // It is critical to the physical link stability NOT to reset (LIP)
1109 // more than absolutely necessary; this is a basic premise of the
1110 // SANMark level 1 spec.
1111 {
1112 ULONG Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >>4;
1113
1114 if( (fcChip->Registers.FMstatus.value & 0x400) // ElasticStore?
1115 &&
1116 !(fcChip->Registers.FMstatus.value & 0x100) // NOT LDn
1117 &&
1118 !(fcChip->Registers.FMstatus.value & 0x1000)) // NOT LF
1119 {
1120 if( (Lpsm != 0) || // not MONITORING? or
1121 !(Lpsm & 0x8) )// not already offline?
1122 {
1123 // now check the particular LST states...
1124 if( (Lpsm == ARBITRATING) || (Lpsm == OPEN) ||
1125 (Lpsm == OPENED) || (Lpsm == XMITTD_CLOSE) ||
1126 (Lpsm == RCVD_CLOSE) )
1127 {
1128 // re-init the loop before it hangs itself!
1129 printk(" #req FMinit on E-S: LPSM %Xh# ",Lpsm);
1130
1131
1132 fcChip->fcStats.FMinits++;
1133 writel( 6, fcChip->Registers.FMcontrol.address); // LIP
1134 }
1135 }
1136 }
1137 else if( fcChip->Registers.FMstatus.value & 0x40000 ) // LST?
1138 {
1139 printk(" #req FMinit on LST, LPSM %Xh# ",Lpsm);
1140
1141 fcChip->fcStats.FMinits++;
1142 writel( 6, fcChip->Registers.FMcontrol.address); // LIP
1143 }
1144 }
1145
1146
1147 // clear only the 'interrupting' type bits for this REG read
1148 writel( (fcChip->Registers.FMstatus.value & 0xff3fff00L),
1149 fcChip->Registers.FMstatus.address);
1150
1151
1152 // copy frame manager status to unused ULONG slot
1153 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] =
1154 fcChip->Registers.FMstatus.value; // (for debugging)
1155
1156
1157 // Load the Frame Manager's error counters. We check them here
1158 // because presumably the link is up and healthy enough for the
1159 // counters to be meaningful (i.e., don't check them while loop
1160 // is initializing).
1161 fcChip->Registers.FMLinkStatus1.value = // get TL's counter
1162 readl(fcChip->Registers.FMLinkStatus1.address);
1163
1164 fcChip->Registers.FMLinkStatus2.value = // get TL's counter
1165 readl(fcChip->Registers.FMLinkStatus2.address);
1166
1167 // Get FM BB_Credit Zero Reg - does not clear on READ
1168 fcChip->Registers.FMBB_CreditZero.value = // get TL's counter
1169 readl(fcChip->Registers.FMBB_CreditZero.address);
1170
1171
1172
1173 fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
1174
1175
1176 // LINK DOWN
1177
1178 if( fcChip->Registers.FMstatus.value & 0x100L ) // Link DOWN bit
1179 {
1180
1181#ifdef IMQ_DEBUG
1182 printk("LinkDn\n");
1183#endif
1184 printk(" #LDn# ");
1185
1186 fcChip->fcStats.linkDown++;
1187
1188 SetTachTOV( cpqfcHBAdata); // must set according to SANMark
1189
1190 // Check the ERQ - force it to be "empty" to prevent Tach
1191 // from sending out frames before we do logins.
1192
1193
1194 if( fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex)
1195 {
1196// printk("#ERQ PI != CI#");
1197 CpqTsFreezeTachlite( fcChip, 1); // freeze ERQ only
1198 fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0;
1199 writel( fcChip->ERQ->base,
1200 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
1201 // re-writing base forces ERQ PI to equal CI
1202
1203 }
1204
1205 // link down transition occurred -- port_ids can change
1206 // on next LinkUp, so we must invalidate current logins
1207 // (and any I/O in progress) until PDISC or PLOGI/PRLI
1208 // completes
1209 {
1210 pLoggedInPort = &fcChip->fcPorts;
1211 while( pLoggedInPort ) // for all ports which are expecting
1212 // PDISC after the next LIP, set the
1213 // logoutTimer
1214 {
1215
1216 if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
1217 {
1218 pLoggedInPort->LOGO_timer = 3; // we want 2 seconds
1219 // but Timer granularity
1220 // is 1 second
1221 }
1222 // suspend any I/O in progress until
1223 // PDISC received...
1224 pLoggedInPort->prli = FALSE; // block FCP-SCSI commands
1225
1226 pLoggedInPort = pLoggedInPort->pNextPort;
1227 } // ... all Previously known ports checked
1228 }
1229
1230 // since any hot plugging device may NOT support LILP frames
1231 // (such as early Tachyon chips), clear this flag indicating
1232 // we shouldn't use (our copy of) a LILP map.
1233 // If we receive an LILP frame, we'll set it again.
1234 fcChip->Options.LILPin = 0; // our LILPmap is invalid
1235 cpqfcHBAdata->PortDiscDone = 0; // must re-validate FC ports!
1236
1237 // also, we want to invalidate (i.e. INITIATOR_ABORT) any
1238 // open Login exchanges, in case the LinkDown happened in the
1239 // middle of logins. It's possible that some ports already
1240 // ACCepted login commands which we have not processed before
1241 // another LinkDown occurred. Any accepted Login exhanges are
1242 // invalidated by LinkDown, even before they are acknowledged.
1243 // It's also possible for a port to have a Queued Reply or Request
1244 // for login which was interrupted by LinkDown; it may come later,
1245 // but it will be unacceptable to us.
1246
1247 // we must scan the entire exchange space, find every Login type
1248 // originated by us, and abort it. This is NOT an abort due to
1249 // timeout, so we don't actually send abort to the other port -
1250 // we just complete it to free up the fcExchange slot.
1251
1252 for( i=TACH_SEST_LEN; i< TACH_MAX_XID; i++)
1253 { // looking for Extended Link Serv.Exchanges
1254 if( Exchanges->fcExchange[i].type == ELS_PDISC ||
1255 Exchanges->fcExchange[i].type == ELS_PLOGI ||
1256 Exchanges->fcExchange[i].type == ELS_PRLI )
1257 {
1258 // ABORT the exchange!
1259#ifdef IMQ_DEBUG
1260 printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n",
1261 i, Exchanges->fcExchange[i].type,
1262 Exchanges->fcExchange[i].fchs.d_id);
1263#endif
1264
1265 Exchanges->fcExchange[i].status |= INITIATOR_ABORT;
1266 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i); // abort on LDn
1267 }
1268 }
1269
1270 }
1271
1272 // ################ LINK UP ##################
1273 if( fcChip->Registers.FMstatus.value & 0x200L ) // Link Up bit
1274 { // AL_PA could have changed
1275
1276 // We need the following code, duplicated from LinkDn condition,
1277 // because it's possible for the Tachyon to re-initialize (hard
1278 // reset) without ever getting a LinkDn indication.
1279 pLoggedInPort = &fcChip->fcPorts;
1280 while( pLoggedInPort ) // for all ports which are expecting
1281 // PDISC after the next LIP, set the
1282 // logoutTimer
1283 {
1284 if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
1285 {
1286 pLoggedInPort->LOGO_timer = 3; // we want 2 seconds
1287 // but Timer granularity
1288 // is 1 second
1289
1290 // suspend any I/O in progress until
1291 // PDISC received...
1292
1293 }
1294 pLoggedInPort = pLoggedInPort->pNextPort;
1295 } // ... all Previously known ports checked
1296
1297 // CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)
1298 fcChip->Registers.rcv_al_pa.value =
1299 readl(fcChip->Registers.rcv_al_pa.address);
1300
1301 // Now, if our acquired address is DIFFERENT from our
1302 // previous one, we are not allow to do PDISC - we
1303 // must go back to PLOGI, which will terminate I/O in
1304 // progress for ALL logged in FC devices...
1305 // (This is highly unlikely).
1306
1307 if( (fcChip->Registers.my_al_pa & 0xFF) !=
1308 ((fcChip->Registers.rcv_al_pa.value >> 16) &0xFF) )
1309 {
1310
1311// printk(" #our HBA port_id changed!# "); // FC port_id changed!!
1312
1313 pLoggedInPort = &fcChip->fcPorts;
1314 while( pLoggedInPort ) // for all ports which are expecting
1315 // PDISC after the next LIP, set the
1316 // logoutTimer
1317 {
1318 pLoggedInPort->pdisc = FALSE;
1319 pLoggedInPort->prli = FALSE;
1320 pLoggedInPort = pLoggedInPort->pNextPort;
1321 } // ... all Previously known ports checked
1322
1323 // when the port_id changes, we must terminate
1324 // all open exchanges.
1325 cpqfcTSTerminateExchange( cpqfcHBAdata, NULL, PORTID_CHANGED);
1326
1327 }
1328
1329 // Replace the entire 24-bit port_id. We only know the
1330 // lower 8 bits (alpa) from Tachyon; if a FLOGI is done,
1331 // we'll get the upper 16-bits from the FLOGI ACC frame.
1332 // If someone plugs into Fabric switch, we'll do FLOGI and
1333 // get full 24-bit port_id; someone could then remove and
1334 // hot-plug us into a dumb hub. If we send a 24-bit PLOGI
1335 // to a "private" loop device, it might blow up.
1336 // Consequently, we force the upper 16-bits of port_id to
1337 // be re-set on every LinkUp transition
1338 fcChip->Registers.my_al_pa =
1339 (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;
1340
1341
1342 // copy frame manager status to unused ULONG slot
1343 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
1344 fcChip->Registers.my_al_pa; // (for debugging)
1345
1346 // for TachLite, we need to write the acquired al_pa
1347 // back into the FMconfig register, because after
1348 // first initialization, the AQ (prev. acq.) bit gets
1349 // set, causing TL FM to use the AL_PA field in FMconfig.
1350 // (In Tachyon, FM writes the acquired AL_PA for us.)
1351 ulBuff = readl( fcChip->Registers.FMconfig.address);
1352 ulBuff &= 0x00ffffffL; // mask out current al_pa
1353 ulBuff |= ( fcChip->Registers.my_al_pa << 24 ); // or in acq. al_pa
1354 fcChip->Registers.FMconfig.value = ulBuff; // copy it back
1355 writel( fcChip->Registers.FMconfig.value, // put in TachLite
1356 fcChip->Registers.FMconfig.address);
1357
1358
1359#ifdef IMQ_DEBUG
1360 printk("#LUp %Xh, FMstat 0x%08X#",
1361 fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);
1362#endif
1363
1364 // also set the WRITE-ONLY My_ID Register (for Fabric
1365 // initialization)
1366 writel( fcChip->Registers.my_al_pa,
1367 fcChip->Registers.ReMapMemBase +TL_MEM_TACH_My_ID);
1368
1369
1370 fcChip->fcStats.linkUp++;
1371
1372 // reset TL statistics counters
1373 // (we ignore these error counters
1374 // while link is down)
1375 ulBuff = // just reset TL's counter
1376 readl( fcChip->Registers.FMLinkStatus1.address);
1377
1378 ulBuff = // just reset TL's counter
1379 readl( fcChip->Registers.FMLinkStatus2.address);
1380
1381 // for initiator, need to start verifying ports (e.g. PDISC)
1382
1383
1384
1385
1386
1387
1388 CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachlite, if Link OK
1389
1390 // Tachyon creates an interesting problem for us on LILP frames.
1391 // Instead of writing the incoming LILP frame into the SFQ before
1392 // indicating LINK UP (the actual order of events), Tachyon tells
1393 // us LINK UP, and later us the LILP. So we delay, then examine the
1394 // IMQ for an Inbound CM (x04); if found, we can set
1395 // LINKACTIVE after processing the LILP. Otherwise, just proceed.
1396 // Since Tachyon imposes this time delay (and doesn't tell us
1397 // what it is), we have to impose a delay before "Peeking" the IMQ
1398 // for Tach hardware (DMA) delivery.
1399 // Processing LILP is required by SANMark
1400 udelay( 1000); // microsec delay waiting for LILP (if it comes)
1401 if( PeekIMQEntry( fcChip, ELS_LILP_FRAME) )
1402 { // found SFQ LILP, which will post LINKACTIVE
1403// printk("skipping LINKACTIVE post\n");
1404
1405 }
1406 else
1407 cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, ulFibreFrame);
1408 }
1409
1410
1411
1412 // ******* Set Fabric Login indication ********
1413 if( fcChip->Registers.FMstatus.value & 0x2000 )
1414 {
1415 printk(" #Fabric# ");
1416 fcChip->Options.fabric = 1;
1417 }
1418 else
1419 fcChip->Options.fabric = 0;
1420
1421
1422
1423 // ******* LIP(F8,x) or BAD AL_PA? ********
1424 if( fcChip->Registers.FMstatus.value & 0x30000L )
1425 {
1426 // copy the error AL_PAs
1427 fcChip->Registers.rcv_al_pa.value =
1428 readl(fcChip->Registers.rcv_al_pa.address);
1429
1430 // Bad AL_PA?
1431 if( fcChip->Registers.FMstatus.value & 0x10000L )
1432 {
1433 PFC_LOGGEDIN_PORT pLoggedInPort;
1434
1435 // copy "BAD" al_pa field
1436 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
1437 (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;
1438
1439 pLoggedInPort = fcFindLoggedInPort( fcChip,
1440 NULL, // DON'T search Scsi Nexus
1441 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1], // port id
1442 NULL, // DON'T search linked list for FC WWN
1443 NULL); // DON'T care about end of list
1444
1445 if( pLoggedInPort )
1446 {
1447 // Just in case we got this BAD_ALPA because a device
1448 // quietly disappeared (can happen on non-managed hubs such
1449 // as the Vixel Rapport 1000),
1450 // do an Implicit Logout. We never expect this on a Logged
1451 // in port (but do expect it on port discovery).
1452 // (As a reasonable alternative, this could be changed to
1453 // simply start the implicit logout timer, giving the device
1454 // several seconds to "come back".)
1455 //
1456 printk(" #BAD alpa %Xh# ",
1457 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);
1458 cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
1459 }
1460 }
1461 // LIP(f8,x)?
1462 if( fcChip->Registers.FMstatus.value & 0x20000L )
1463 {
1464 // for debugging, copy al_pa field
1465 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] =
1466 (fcChip->Registers.rcv_al_pa.value & 0xffL);
1467 // get the other port's al_pa
1468 // (one that sent LIP(F8,?) )
1469 }
1470 }
1471
1472 // Elastic store err
1473 if( fcChip->Registers.FMstatus.value & 0x400L )
1474 {
1475 // don't count e-s if loop is down!
1476 if( !(USHORT)(fcChip->Registers.FMstatus.value & 0x80) )
1477 fcChip->fcStats.e_stores++;
1478
1479 }
1480 }
1481 break;
1482
1483
1484 case INBOUND_FCP_XCHG_COMPLETION: // 0x0C
1485
1486 // Remarks:
1487 // On Tachlite TL/TS, we get this message when the data phase
1488 // of a SEST inbound transfer is complete. For example, if a WRITE command
1489 // was received with OX_ID 0, we might respond with XFER_RDY with
1490 // RX_ID 8001. This would start the SEST controlled data phases. When
1491 // all data frames are received, we get this inbound completion. This means
1492 // we should send a status frame to complete the status phase of the
1493 // FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data
1494 // frames.
1495 // See Outbound CM discussion of x_IDs
1496 // Psuedo Code
1497 // Get SEST index (x_ID)
1498 // x_ID out of range, return (err condition)
1499 // set status bits from 2nd dword
1500 // free transactionID & SEST entry
1501 // call fcComplete with transactionID & status
1502
1503 ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];
1504 x_ID = ulBuff & 0x7fffL; // lower 14 bits SEST_Index/Trans_ID
1505 // (mask out MSB "direction" bit)
1506 // Range check CM OX/RX_ID value...
1507 if( x_ID < TACH_SEST_LEN ) // don't go beyond SEST array space
1508 {
1509
1510//#define FCP_COMPLETION_DBG 1
1511#ifdef FCP_COMPLETION_DBG
1512 printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n",
1513 x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);
1514#endif
1515 if( ulBuff & 0x08000000L ) // RPC -Response Phase Complete - or -
1516 // time to send response frame?
1517 RPCset = 1; // (SEST transaction)
1518 else
1519 RPCset = 0;
1520 // set the status for this Inbound SCSI transaction's ID
1521 dwStatus = 0L;
1522 if( ulBuff & 0x70000000L ) // any errs?
1523 {
1524
1525 if( ulBuff & 0x40000000L )
1526 dwStatus |= LINKFAIL_RX;
1527
1528 if( ulBuff & 0x20000000L )
1529 dwStatus |= COUNT_ERROR;
1530
1531 if( ulBuff & 0x10000000L )
1532 dwStatus |= OVERFLOW;
1533 }
1534
1535
1536 // FCP transaction done - copy status
1537 Exchanges->fcExchange[ x_ID ].status = dwStatus;
1538
1539
1540 // Did the exchange get an FCP-RSP response frame?
1541 // (Note the little endian/big endian FC payload difference)
1542
1543 if( RPCset ) // SEST transaction Response frame rec'd
1544 {
1545 // complete the command in our driver...
1546 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev,fcChip, x_ID);
1547
1548 } // end "RPCset"
1549
1550 else // ("target" logic)
1551 {
1552 // Tachlite says all data frames have been received - now it's time
1553 // to analyze data transfer (successful?), then send a response
1554 // frame for this exchange
1555
1556 ulFibreFrame[0] = x_ID; // copy for later reference
1557
1558 // if this was a TWE, we have to send satus response
1559 if( Exchanges->fcExchange[ x_ID].type == SCSI_TWE )
1560 {
1561// fcPutScsiQue( cpqfcHBAdata,
1562// NEED_FCP_RSP, ulFibreFrame); // (ulFibreFrame not used here)
1563 }
1564 }
1565 }
1566 else // ERROR CONDITION! bogus x_ID in completion message
1567 {
1568 printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);
1569 }
1570
1571 break;
1572
1573
1574
1575
1576 case INBOUND_SCSI_DATA_COMMAND:
1577 case BAD_SCSI_FRAME:
1578 case INB_SCSI_STATUS_COMPLETION:
1579 case BUFFER_PROCESSED_COMPLETION:
1580 break;
1581 }
1582
1583 // Tachyon is producing;
1584 // we are consuming
1585 fcChip->IMQ->consumerIndex++; // increment OUR consumerIndex
1586 if( fcChip->IMQ->consumerIndex >= IMQ_LEN)// check for rollover
1587 fcChip->IMQ->consumerIndex = 0L; // reset it
1588
1589
1590 if( fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex )
1591 { // all Messages are processed -
1592 iStatus = 0; // no more messages to process
1593
1594 }
1595 else
1596 iStatus = 1; // more messages to process
1597
1598 // update TachLite's ConsumerIndex... (clears INTA_L)
1599 // NOTE: according to TL/TS UG, the
1600 // "host must return completion messages in sequential order".
1601 // Does this mean one at a time, in the order received? We
1602 // presume so.
1603
1604 writel( fcChip->IMQ->consumerIndex,
1605 (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
1606
1607#if IMQ_DEBUG
1608 printk("Process IMQ: writing consumer ndx %d\n ",
1609 fcChip->IMQ->consumerIndex);
1610 printk("PI %X, CI %X\n",
1611 fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex );
1612#endif
1613
1614
1615
1616 }
1617 else
1618 {
1619 // hmmm... why did we get interrupted/called with no message?
1620 iStatus = -1; // nothing to process
1621#if IMQ_DEBUG
1622 printk("Process IMQ: no message PI %Xh CI %Xh",
1623 fcChip->IMQ->producerIndex,
1624 fcChip->IMQ->consumerIndex);
1625#endif
1626 }
1627
1628 LEAVE("ProcessIMQEntry");
1629
1630 return iStatus;
1631}
1632
1633
1634
1635
1636
1637// This routine initializes Tachyon according to the following
1638// options (opcode1):
1639// 1 - RESTART Tachyon, simulate power on condition by shutting
1640// down laser, resetting the hardware, de-allocating all buffers;
1641// continue
1642// 2 - Config Tachyon / PCI registers;
1643// continue
1644// 3 - Allocating memory and setting Tachyon queues (write Tachyon regs);
1645// continue
1646// 4 - Config frame manager registers, initialize, turn on laser
1647//
1648// Returns:
1649// -1 on fatal error
1650// 0 on success
1651
1652int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2)
1653{
1654 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
1655 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1656 ULONG ulBuff;
1657 UCHAR bBuff;
1658 int iStatus=-1; // assume failure
1659
1660 ENTER("InitializeTachLite");
1661
1662 // verify board's base address (sanity check)
1663
1664 if( !fcChip->Registers.ReMapMemBase) // NULL address for card?
1665 return -1; // FATAL error!
1666
1667
1668
1669 switch( opcode1 )
1670 {
1671 case 1: // restore hardware to power-on (hard) restart
1672
1673
1674 iStatus = fcChip->ResetTachyon(
1675 cpqfcHBAdata, opcode2); // laser off, reset hardware
1676 // de-allocate aligned buffers
1677
1678
1679/* TBD // reset FC link Q (producer and consumer = 0)
1680 fcLinkQReset(cpqfcHBAdata);
1681
1682*/
1683
1684 if( iStatus )
1685 break;
1686
1687 case 2: // Config PCI/Tachyon registers
1688 // NOTE: For Tach TL/TS, bit 31 must be set to 1. For TS chips, a read
1689 // of bit 31 indicates state of M66EN signal; if 1, chip may run at
1690 // 33-66MHz (see TL/TS UG, pg 159)
1691
1692 ulBuff = 0x80000000; // TachLite Configuration Register
1693
1694 writel( ulBuff, fcChip->Registers.TYconfig.address);
1695// ulBuff = 0x0147L; // CpqTs PCI CFGCMD register
1696// WritePCIConfiguration( fcChip->Backplane.bus,
1697// fcChip->Backplane.slot, TLCFGCMD, ulBuff, 4);
1698// ulBuff = 0x0L; // test!
1699// ReadPCIConfiguration( fcChip->Backplane.bus,
1700// fcChip->Backplane.slot, TLCFGCMD, &ulBuff, 4);
1701
1702 // read back for reference...
1703 fcChip->Registers.TYconfig.value =
1704 readl( fcChip->Registers.TYconfig.address );
1705
1706 // what is the PCI bus width?
1707 pci_read_config_byte( cpqfcHBAdata->PciDev,
1708 0x43, // PCIMCTR offset
1709 &bBuff);
1710
1711 fcChip->Registers.PCIMCTR = bBuff;
1712
1713 // set string identifying the chip on the circuit board
1714
1715 fcChip->Registers.TYstatus.value =
1716 readl( fcChip->Registers.TYstatus.address);
1717
1718 {
1719// Now that we are supporting multiple boards, we need to change
1720// this logic to check for PCI vendor/device IDs...
1721// for now, quick & dirty is simply checking Chip rev
1722
1723 ULONG RevId = (fcChip->Registers.TYstatus.value &0x3E0)>>5;
1724 UCHAR Minor = (UCHAR)(RevId & 0x3);
1725 UCHAR Major = (UCHAR)((RevId & 0x1C) >>2);
1726
1727 /* printk(" HBA Tachyon RevId %d.%d\n", Major, Minor); */
1728 if( (Major == 1) && (Minor == 2) )
1729 {
1730 sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12);
1731
1732 }
1733 else if( (Major == 1) && (Minor == 3) )
1734 {
1735 sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13);
1736 }
1737 else if( (Major == 2) && (Minor == 1) )
1738 {
1739 sprintf( cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21);
1740 }
1741 else
1742 sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN);
1743 }
1744
1745
1746
1747 case 3: // allocate mem, set Tachyon Que registers
1748 iStatus = CpqTsCreateTachLiteQues( cpqfcHBAdata, opcode2);
1749
1750 if( iStatus )
1751 break;
1752
1753 // now that the Queues exist, Tach can DMA to them, so
1754 // we can begin processing INTs
1755 // INTEN register - enable INT (TachLite interrupt)
1756 writeb( 0x1F, fcChip->Registers.ReMapMemBase + IINTEN);
1757
1758 // Fall through
1759 case 4: // Config Fame Manager, Init Loop Command, laser on
1760
1761 // L_PORT or loopback
1762 // depending on Options
1763 iStatus = CpqTsInitializeFrameManager( fcChip,0 );
1764 if( iStatus )
1765 {
1766 // failed to initialize Frame Manager
1767 break;
1768 }
1769
1770 default:
1771 break;
1772 }
1773 LEAVE("InitializeTachLite");
1774
1775 return iStatus;
1776}
1777
1778
1779
1780
1781// Depending on the type of platform memory allocation (e.g. dynamic),
1782// it's probably best to free memory in opposite order as it was allocated.
1783// Order of allocation: see other function
1784
1785
1786int CpqTsDestroyTachLiteQues( void *pHBA, int opcode)
1787{
1788 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
1789 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1790 USHORT i, iStatus=0;
1791 void* vPtr; // mem Align manager sets this to the freed address on success
1792 unsigned long ulPtr; // for 64-bit pointer cast (e.g. Alpa machine)
1793 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1794 PSGPAGES j, next;
1795
1796 ENTER("DestroyTachLiteQues");
1797
1798 if( fcChip->SEST )
1799 {
1800 // search out and free Pool for Extended S/G list pages
1801
1802 for( i=0; i < TACH_SEST_LEN; i++) // for each exchange
1803 {
1804 // It's possible that extended S/G pages were allocated, mapped, and
1805 // not cleared due to error conditions or O/S driver termination.
1806 // Make sure they're all gone.
1807 if (Exchanges->fcExchange[i].Cmnd != NULL)
1808 cpqfc_pci_unmap(cpqfcHBAdata->PciDev, Exchanges->fcExchange[i].Cmnd,
1809 fcChip, i); // undo DMA mappings.
1810
1811 for (j=fcChip->SEST->sgPages[i] ; j != NULL ; j = next) {
1812 next = j->next;
1813 kfree(j);
1814 }
1815 fcChip->SEST->sgPages[i] = NULL;
1816 }
1817 ulPtr = (unsigned long)fcChip->SEST;
1818 vPtr = fcMemManager( cpqfcHBAdata->PciDev,
1819 &cpqfcHBAdata->dynamic_mem[0],
1820 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1821 fcChip->SEST = 0L; // null invalid ptr
1822 if( !vPtr )
1823 {
1824 printk("SEST mem not freed\n");
1825 iStatus = -1;
1826 }
1827 }
1828
1829 if( fcChip->SFQ )
1830 {
1831
1832 ulPtr = (unsigned long)fcChip->SFQ;
1833 vPtr = fcMemManager( cpqfcHBAdata->PciDev,
1834 &cpqfcHBAdata->dynamic_mem[0],
1835 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1836 fcChip->SFQ = 0L; // null invalid ptr
1837 if( !vPtr )
1838 {
1839 printk("SFQ mem not freed\n");
1840 iStatus = -2;
1841 }
1842 }
1843
1844
1845 if( fcChip->IMQ )
1846 {
1847 // clear Indexes to show empty Queue
1848 fcChip->IMQ->producerIndex = 0;
1849 fcChip->IMQ->consumerIndex = 0;
1850
1851 ulPtr = (unsigned long)fcChip->IMQ;
1852 vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
1853 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1854 fcChip->IMQ = 0L; // null invalid ptr
1855 if( !vPtr )
1856 {
1857 printk("IMQ mem not freed\n");
1858 iStatus = -3;
1859 }
1860 }
1861
1862 if( fcChip->ERQ ) // release memory blocks used by the queues
1863 {
1864 ulPtr = (unsigned long)fcChip->ERQ;
1865 vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
1866 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1867 fcChip->ERQ = 0L; // null invalid ptr
1868 if( !vPtr )
1869 {
1870 printk("ERQ mem not freed\n");
1871 iStatus = -4;
1872 }
1873 }
1874
1875 // free up the primary EXCHANGES struct and Link Q
1876 cpqfc_free_dma_consistent(cpqfcHBAdata);
1877
1878 LEAVE("DestroyTachLiteQues");
1879
1880 return iStatus; // non-zero (failed) if any memory not freed
1881}
1882
1883
1884
1885
1886
1887// The SFQ is an array with SFQ_LEN length, each element (QEntry)
1888// with eight 32-bit words. TachLite places incoming FC frames (i.e.
1889// a valid FC frame with our AL_PA ) in contiguous SFQ entries
1890// and sends a completion message telling the host where the frame is
1891// in the que.
1892// This function copies the current (or oldest not-yet-processed) QEntry to
1893// a caller's contiguous buffer and updates the Tachyon chip's consumer index
1894//
1895// NOTE:
1896// An FC frame may consume one or many SFQ entries. We know the total
1897// length from the completion message. The caller passes a buffer large
1898// enough for the complete message (max 2k).
1899
1900static void CpqTsGetSFQEntry(
1901 PTACHYON fcChip,
1902 USHORT producerNdx,
1903 ULONG *ulDestPtr, // contiguous destination buffer
1904 BOOLEAN UpdateChip)
1905{
1906 ULONG total_bytes=0;
1907 ULONG consumerIndex = fcChip->SFQ->consumerIndex;
1908
1909 // check passed copy of SFQ producer index -
1910 // is a new message waiting for us?
1911 // equal indexes means SFS is copied
1912
1913 while( producerNdx != consumerIndex )
1914 { // need to process message
1915 total_bytes += 64; // maintain count to prevent writing past buffer
1916 // don't allow copies over Fibre Channel defined length!
1917 if( total_bytes <= 2048 )
1918 {
1919 memcpy( ulDestPtr,
1920 &fcChip->SFQ->QEntry[consumerIndex],
1921 64 ); // each SFQ entry is 64 bytes
1922 ulDestPtr += 16; // advance pointer to next 64 byte block
1923 }
1924 // Tachyon is producing,
1925 // and we are consuming
1926
1927 if( ++consumerIndex >= SFQ_LEN)// check for rollover
1928 consumerIndex = 0L; // reset it
1929 }
1930
1931 // if specified, update the Tachlite chip ConsumerIndex...
1932 if( UpdateChip )
1933 {
1934 fcChip->SFQ->consumerIndex = consumerIndex;
1935 writel( fcChip->SFQ->consumerIndex,
1936 fcChip->Registers.SFQconsumerIndex.address);
1937 }
1938}
1939
1940
1941
1942// TachLite routinely freezes it's core ques - Outbound FIFO, Inbound FIFO,
1943// and Exchange Request Queue (ERQ) on error recover -
1944// (e.g. whenever a LIP occurs). Here
1945// we routinely RESUME by clearing these bits, but only if the loop is up
1946// to avoid ERROR IDLE messages forever.
1947
1948void CpqTsUnFreezeTachlite( void *pChip, int type )
1949{
1950 PTACHYON fcChip = (PTACHYON)pChip;
1951 fcChip->Registers.TYcontrol.value =
1952 readl(fcChip->Registers.TYcontrol.address);
1953
1954 // (bit 4 of value is GBIC LASER)
1955 // if we 'unfreeze' the core machines before the loop is healthy
1956 // (i.e. FLT, OS, LS failure bits set in FMstatus)
1957 // we can get 'error idle' messages forever. Verify that
1958 // FMstatus (Link Status) is OK before unfreezing.
1959
1960 if( !(fcChip->Registers.FMstatus.value & 0x07000000L) && // bits clear?
1961 !(fcChip->Registers.FMstatus.value & 0x80 )) // Active LPSM?
1962 {
1963 fcChip->Registers.TYcontrol.value &= ~0x300L; // clear FEQ, FFA
1964 if( type == 1 ) // unfreeze ERQ only
1965 {
1966// printk("Unfreezing ERQ\n");
1967 fcChip->Registers.TYcontrol.value |= 0x10000L; // set REQ
1968 }
1969 else // unfreeze both ERQ and FCP-ASSIST (SEST)
1970 {
1971// printk("Unfreezing ERQ & FCP-ASSIST\n");
1972
1973 // set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ
1974 fcChip->Registers.TYcontrol.value |= 0x70000L; // set ROF, RIF, REQ
1975 }
1976
1977 writel( fcChip->Registers.TYcontrol.value,
1978 fcChip->Registers.TYcontrol.address);
1979
1980 }
1981 // readback for verify (TachLite still frozen?)
1982 fcChip->Registers.TYstatus.value =
1983 readl(fcChip->Registers.TYstatus.address);
1984}
1985
1986
1987// Whenever an FC Exchange Abort is required, we must manipulate the
1988// Host/Tachyon shared memory SEST table. Before doing this, we
1989// must freeze Tachyon, which flushes certain buffers and ensure we
1990// can manipulate the SEST without contention.
1991// This freeze function will result in FCP & ERQ FROZEN completion
1992// messages (per argument "type").
1993
1994void CpqTsFreezeTachlite( void *pChip, int type )
1995{
1996 PTACHYON fcChip = (PTACHYON)pChip;
1997 fcChip->Registers.TYcontrol.value =
1998 readl(fcChip->Registers.TYcontrol.address);
1999
2000 //set FFA, FEQ - freezes SCSI assist and ERQ
2001 if( type == 1) // freeze ERQ only
2002 fcChip->Registers.TYcontrol.value |= 0x100L; // (bit 4 is laser)
2003 else // freeze both FCP assists (SEST) and ERQ
2004 fcChip->Registers.TYcontrol.value |= 0x300L; // (bit 4 is laser)
2005
2006 writel( fcChip->Registers.TYcontrol.value,
2007 fcChip->Registers.TYcontrol.address);
2008
2009}
2010
2011
2012
2013
2014// TL has two Frame Manager Link Status Registers, with three 8-bit
2015// fields each. These eight bit counters are cleared after each read,
2016// so we define six 32-bit accumulators for these TL counters. This
2017// function breaks out each 8-bit field and adds the value to the existing
2018// sum. (s/w counters cleared independently)
2019
2020void fcParseLinkStatusCounters(PTACHYON fcChip)
2021{
2022 UCHAR bBuff;
2023 ULONG ulBuff;
2024
2025
2026// The BB0 timer usually increments when TL is initialized, resulting
2027// in an initially bogus count. If our own counter is ZERO, it means we
2028// are reading this thing for the first time, so we ignore the first count.
2029// Also, reading the register does not clear it, so we have to keep an
2030// additional static counter to detect rollover (yuk).
2031
2032 if( fcChip->fcStats.lastBB0timer == 0L) // TL was reset? (ignore 1st values)
2033 {
2034 // get TL's register counter - the "last" count
2035 fcChip->fcStats.lastBB0timer =
2036 fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
2037 }
2038 else // subsequent pass - check for rollover
2039 {
2040 // "this" count
2041 ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
2042 if( fcChip->fcStats.lastBB0timer > ulBuff ) // rollover happened
2043 {
2044 // counter advanced to max...
2045 fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer);
2046 fcChip->fcStats.BB0_Timer += ulBuff; // plus some more
2047
2048
2049 }
2050 else // no rollover -- more counts or no change
2051 {
2052 fcChip->fcStats.BB0_Timer += (ulBuff - fcChip->fcStats.lastBB0timer);
2053
2054 }
2055
2056 fcChip->fcStats.lastBB0timer = ulBuff;
2057 }
2058
2059
2060
2061 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 24);
2062 fcChip->fcStats.LossofSignal += bBuff;
2063
2064 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 16);
2065 fcChip->fcStats.BadRXChar += bBuff;
2066
2067 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 8);
2068 fcChip->fcStats.LossofSync += bBuff;
2069
2070
2071 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 24);
2072 fcChip->fcStats.Rx_EOFa += bBuff;
2073
2074 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 16);
2075 fcChip->fcStats.Dis_Frm += bBuff;
2076
2077 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 8);
2078 fcChip->fcStats.Bad_CRC += bBuff;
2079}
2080
2081
2082void cpqfcTSClearLinkStatusCounters(PTACHYON fcChip)
2083{
2084 ENTER("ClearLinkStatusCounters");
2085 memset( &fcChip->fcStats, 0, sizeof( FCSTATS));
2086 LEAVE("ClearLinkStatusCounters");
2087
2088}
2089
2090
2091
2092
2093// The following function reads the I2C hardware to get the adapter's
2094// World Wide Name (WWN).
2095// If the WWN is "500805f1fadb43e8" (as printed on the card), the
2096// Tachyon WWN_hi (32-bit) register is 500805f1, and WWN_lo register
2097// is fadb43e8.
2098// In the NVRAM, the bytes appear as:
2099// [2d] ..
2100// [2e] ..
2101// [2f] 50
2102// [30] 08
2103// [31] 05
2104// [32] f1
2105// [33] fa
2106// [34] db
2107// [35] 43
2108// [36] e8
2109//
2110// In the Fibre Channel (Big Endian) format, the FC-AL LISM frame will
2111// be correctly loaded by Tachyon silicon. In the login payload, bytes
2112// must be correctly swapped for Big Endian format.
2113
2114int CpqTsReadWriteWWN( PVOID pChip, int Read)
2115{
2116 PTACHYON fcChip = (PTACHYON)pChip;
2117#define NVRAM_SIZE 512
2118 unsigned short i, count = NVRAM_SIZE;
2119 UCHAR nvRam[NVRAM_SIZE], WWNbuf[8];
2120 ULONG ulBuff;
2121 int iStatus=-1; // assume failure
2122 int WWNoffset;
2123
2124 ENTER("ReadWriteWWN");
2125 // Now try to read the WWN from the adapter's NVRAM
2126
2127 if( Read ) // READing NVRAM WWN?
2128 {
2129 ulBuff = cpqfcTS_ReadNVRAM( fcChip->Registers.TYstatus.address,
2130 fcChip->Registers.TYcontrol.address,
2131 count, &nvRam[0] );
2132
2133 if( ulBuff ) // NVRAM read successful?
2134 {
2135 iStatus = 0; // success!
2136
2137 // for engineering/ prototype boards, the data may be
2138 // invalid (GIGO, usually all "FF"); this prevents the
2139 // parse routine from working correctly, which means
2140 // nothing will be written to our passed buffer.
2141
2142 WWNoffset = cpqfcTS_GetNVRAM_data( WWNbuf, nvRam );
2143
2144 if( !WWNoffset ) // uninitialized NVRAM -- copy bytes directly
2145 {
2146 printk( "CAUTION: Copying NVRAM data on fcChip\n");
2147 for( i= 0; i < 8; i++)
2148 WWNbuf[i] = nvRam[i +0x2f]; // dangerous! some formats won't work
2149 }
2150
2151 fcChip->Registers.wwn_hi = 0L;
2152 fcChip->Registers.wwn_lo = 0L;
2153 for( i=0; i<4; i++) // WWN bytes are big endian in NVRAM
2154 {
2155 ulBuff = 0L;
2156 ulBuff = (ULONG)(WWNbuf[i]) << (8 * (3-i));
2157 fcChip->Registers.wwn_hi |= ulBuff;
2158 }
2159 for( i=0; i<4; i++) // WWN bytes are big endian in NVRAM
2160 {
2161 ulBuff = 0L;
2162 ulBuff = (ULONG)(WWNbuf[i+4]) << (8 * (3-i));
2163 fcChip->Registers.wwn_lo |= ulBuff;
2164 }
2165 } // done reading
2166 else
2167 {
2168
2169 printk( "cpqfcTS: NVRAM read failed\n");
2170
2171 }
2172 }
2173
2174 else // WRITE
2175 {
2176
2177 // NOTE: WRITE not supported & not used in released driver.
2178
2179
2180 printk("ReadWriteNRAM: can't write NVRAM; aborting write\n");
2181 }
2182
2183 LEAVE("ReadWriteWWN");
2184 return iStatus;
2185}
2186
2187
2188
2189
2190
2191// The following function reads or writes the entire "NVRAM" contents of
2192// the I2C hardware (i.e. the NM24C03). Note that HP's 5121A (TS 66Mhz)
2193// adapter does not use the NM24C03 chip, so this function only works on
2194// Compaq's adapters.
2195
2196int CpqTsReadWriteNVRAM( PVOID pChip, PVOID buf, int Read)
2197{
2198 PTACHYON fcChip = (PTACHYON)pChip;
2199#define NVRAM_SIZE 512
2200 ULONG ulBuff;
2201 UCHAR *ucPtr = buf; // cast caller's void ptr to UCHAR array
2202 int iStatus=-1; // assume failure
2203
2204
2205 if( Read ) // READing NVRAM?
2206 {
2207 ulBuff = cpqfcTS_ReadNVRAM( // TRUE on success
2208 fcChip->Registers.TYstatus.address,
2209 fcChip->Registers.TYcontrol.address,
2210 256, // bytes to write
2211 ucPtr ); // source ptr
2212
2213
2214 if( ulBuff )
2215 iStatus = 0; // success
2216 else
2217 {
2218#ifdef DBG
2219 printk( "CAUTION: NVRAM read failed\n");
2220#endif
2221 }
2222 } // done reading
2223
2224 else // WRITING NVRAM
2225 {
2226
2227 printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n");
2228 }
2229
2230 return iStatus;
2231}
diff --git a/drivers/scsi/cpqfcTSi2c.c b/drivers/scsi/cpqfcTSi2c.c
deleted file mode 100644
index b38a6a9a55a3..000000000000
--- a/drivers/scsi/cpqfcTSi2c.c
+++ /dev/null
@@ -1,493 +0,0 @@
1/* Copyright(c) 2000, Compaq Computer Corporation
2 * Fibre Channel Host Bus Adapter
3 * 64-bit, 66MHz PCI
4 * Originally developed and tested on:
5 * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ...
6 * SP# P225CXCBFIEL6T, Rev XC
7 * SP# 161290-001, Rev XD
8 * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
13 * later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 * Written by Don Zimmerman
20*/
21// These functions control the NVRAM I2C hardware on
22// non-intelligent Fibre Host Adapters.
23// The primary purpose is to read the HBA's NVRAM to get adapter's
24// manufactured WWN to copy into Tachyon chip registers
25// Orignal source author unknown
26
27#include <linux/types.h>
28enum boolean { FALSE, TRUE } ;
29
30
31#ifndef UCHAR
32typedef __u8 UCHAR;
33#endif
34#ifndef BOOLEAN
35typedef __u8 BOOLEAN;
36#endif
37#ifndef USHORT
38typedef __u16 USHORT;
39#endif
40#ifndef ULONG
41typedef __u32 ULONG;
42#endif
43
44
45#include <linux/string.h>
46#include <linux/pci.h>
47#include <linux/delay.h>
48#include <linux/sched.h>
49#include <asm/io.h> // struct pt_regs for IRQ handler & Port I/O
50
51#include "cpqfcTSchip.h"
52
53static void tl_i2c_tx_byte( void* GPIOout, UCHAR data );
54/*static BOOLEAN tl_write_i2c_page_portion( void* GPIOin, void* GPIOout,
55 USHORT startOffset, // e.g. 0x2f for WWN start
56 USHORT count,
57 UCHAR *buf );
58*/
59
60//
61// Tachlite GPIO2, GPIO3 (I2C) DEFINES
62// The NVRAM chip NM24C03 defines SCL (serial clock) and SDA (serial data)
63// GPIO2 drives SDA, and GPIO3 drives SCL
64//
65// Since Tachlite inverts the state of the GPIO 0-3 outputs, SET writes 0
66// and clear writes 1. The input lines (read in TL status) is NOT inverted
67// This really helps confuse the code and debugging.
68
69#define SET_DATA_HI 0x0
70#define SET_DATA_LO 0x8
71#define SET_CLOCK_HI 0x0
72#define SET_CLOCK_LO 0x4
73
74#define SENSE_DATA_HI 0x8
75#define SENSE_DATA_LO 0x0
76#define SENSE_CLOCK_HI 0x4
77#define SENSE_CLOCK_LO 0x0
78
79#define SLAVE_READ_ADDRESS 0xA1
80#define SLAVE_WRITE_ADDRESS 0xA0
81
82
83static void i2c_delay(ULONG mstime);
84static void tl_i2c_clock_pulse( UCHAR , void* GPIOout);
85static UCHAR tl_read_i2c_data( void* );
86
87
88//-----------------------------------------------------------------------------
89//
90// Name: I2C_RX_ACK
91//
92// This routine receives an acknowledge over the I2C bus.
93//
94//-----------------------------------------------------------------------------
95static unsigned short tl_i2c_rx_ack( void* GPIOin, void* GPIOout )
96{
97 unsigned long value;
98
99 // do clock pulse, let data line float high
100 tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
101
102 // slave must drive data low for acknowledge
103 value = tl_read_i2c_data( GPIOin);
104 if (value & SENSE_DATA_HI )
105 return( FALSE );
106
107 return( TRUE );
108}
109//-----------------------------------------------------------------------------
110//
111// Name: READ_I2C_REG
112//
113// This routine reads the I2C control register using the global
114// IO address stored in gpioreg.
115//
116//-----------------------------------------------------------------------------
117static UCHAR tl_read_i2c_data( void* gpioreg )
118{
119 return( (UCHAR)(readl( gpioreg ) & 0x08L) ); // GPIO3
120}
121//-----------------------------------------------------------------------------
122//
123// Name: WRITE_I2C_REG
124//
125// This routine writes the I2C control register using the global
126// IO address stored in gpioreg.
127// In Tachlite, we don't want to modify other bits in TL Control reg.
128//
129//-----------------------------------------------------------------------------
130static void tl_write_i2c_reg( void* gpioregOUT, UCHAR value )
131{
132 ULONG temp;
133
134 // First read the register and clear out the old bits
135 temp = readl( gpioregOUT ) & 0xfffffff3L;
136
137 // Now or in the new data and send it back out
138 writel( temp | value, gpioregOUT);
139}
140//-----------------------------------------------------------------------------
141//
142// Name: I2C_TX_START
143//
144// This routine transmits a start condition over the I2C bus.
145// 1. Set SCL (clock, GPIO2) HIGH, set SDA (data, GPIO3) HIGH,
146// wait 5us to stabilize.
147// 2. With SCL still HIGH, drive SDA low. The low transition marks
148// the start condition to NM24Cxx (the chip)
149// NOTE! In TL control reg., output 1 means chip sees LOW
150//
151//-----------------------------------------------------------------------------
152static unsigned short tl_i2c_tx_start( void* GPIOin, void* GPIOout )
153{
154 unsigned short i;
155 ULONG value;
156
157 if ( !(tl_read_i2c_data(GPIOin) & SENSE_DATA_HI))
158 {
159 // start with clock high, let data float high
160 tl_write_i2c_reg( GPIOout, SET_DATA_HI | SET_CLOCK_HI );
161
162 // keep sending clock pulses if slave is driving data line
163 for (i = 0; i < 10; i++)
164 {
165 tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
166
167 if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
168 break;
169 }
170
171 // if he's still driving data low after 10 clocks, abort
172 value = tl_read_i2c_data( GPIOin ); // read status
173 if (!(value & 0x08) )
174 return( FALSE );
175 }
176
177
178 // To START, bring data low while clock high
179 tl_write_i2c_reg( GPIOout, SET_CLOCK_HI | SET_DATA_LO );
180
181 i2c_delay(0);
182
183 return( TRUE ); // TX start successful
184}
185//-----------------------------------------------------------------------------
186//
187// Name: I2C_TX_STOP
188//
189// This routine transmits a stop condition over the I2C bus.
190//
191//-----------------------------------------------------------------------------
192
193static unsigned short tl_i2c_tx_stop( void* GPIOin, void* GPIOout )
194{
195 int i;
196
197 for (i = 0; i < 10; i++)
198 {
199 // Send clock pulse, drive data line low
200 tl_i2c_clock_pulse( SET_DATA_LO, GPIOout );
201
202 // To STOP, bring data high while clock high
203 tl_write_i2c_reg( GPIOout, SET_DATA_HI | SET_CLOCK_HI );
204
205 // Give the data line time to float high
206 i2c_delay(0);
207
208 // If slave is driving data line low, there's a problem; retry
209 if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
210 return( TRUE ); // TX STOP successful!
211 }
212
213 return( FALSE ); // error
214}
215//-----------------------------------------------------------------------------
216//
217// Name: I2C_TX_uchar
218//
219// This routine transmits a byte across the I2C bus.
220//
221//-----------------------------------------------------------------------------
222static void tl_i2c_tx_byte( void* GPIOout, UCHAR data )
223{
224 UCHAR bit;
225
226 for (bit = 0x80; bit; bit >>= 1)
227 {
228 if( data & bit )
229 tl_i2c_clock_pulse( (UCHAR)SET_DATA_HI, GPIOout);
230 else
231 tl_i2c_clock_pulse( (UCHAR)SET_DATA_LO, GPIOout);
232 }
233}
234//-----------------------------------------------------------------------------
235//
236// Name: I2C_RX_uchar
237//
238// This routine receives a byte across the I2C bus.
239//
240//-----------------------------------------------------------------------------
241static UCHAR tl_i2c_rx_byte( void* GPIOin, void* GPIOout )
242{
243 UCHAR bit;
244 UCHAR data = 0;
245
246
247 for (bit = 0x80; bit; bit >>= 1) {
248 // do clock pulse, let data line float high
249 tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
250
251 // read data line
252 if ( tl_read_i2c_data( GPIOin) & 0x08 )
253 data |= bit;
254 }
255
256 return (data);
257}
258//*****************************************************************************
259//*****************************************************************************
260// Function: read_i2c_nvram
261// Arguments: UCHAR count number of bytes to read
262// UCHAR *buf area to store the bytes read
263// Returns: 0 - failed
264// 1 - success
265//*****************************************************************************
266//*****************************************************************************
267unsigned long cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count,
268 UCHAR *buf )
269{
270 unsigned short i;
271
272 if( !( tl_i2c_tx_start(GPIOin, GPIOout) ))
273 return FALSE;
274
275 // Select the NVRAM for "dummy" write, to set the address
276 tl_i2c_tx_byte( GPIOout , SLAVE_WRITE_ADDRESS );
277 if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
278 return( FALSE );
279
280 // Now send the address where we want to start reading
281 tl_i2c_tx_byte( GPIOout , 0 );
282 if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
283 return( FALSE );
284
285 // Send a repeated start condition and select the
286 // slave for reading now.
287 if( tl_i2c_tx_start(GPIOin, GPIOout) )
288 tl_i2c_tx_byte( GPIOout, SLAVE_READ_ADDRESS );
289
290 if ( !tl_i2c_rx_ack(GPIOin, GPIOout) )
291 return( FALSE );
292
293 // this loop will now read out the data and store it
294 // in the buffer pointed to by buf
295 for ( i=0; i<count; i++)
296 {
297 *buf++ = tl_i2c_rx_byte(GPIOin, GPIOout);
298
299 // Send ACK by holding data line low for 1 clock
300 if ( i < (count-1) )
301 tl_i2c_clock_pulse( 0x08, GPIOout );
302 else {
303 // Don't send ack for final byte
304 tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
305 }
306 }
307
308 tl_i2c_tx_stop(GPIOin, GPIOout);
309
310 return( TRUE );
311}
312
313//****************************************************************
314//
315//
316//
317// routines to set and clear the data and clock bits
318//
319//
320//
321//****************************************************************
322
323static void tl_set_clock(void* gpioreg)
324{
325 ULONG ret_val;
326
327 ret_val = readl( gpioreg );
328 ret_val &= 0xffffffFBL; // clear GPIO2 (SCL)
329 writel( ret_val, gpioreg);
330}
331
332static void tl_clr_clock(void* gpioreg)
333{
334 ULONG ret_val;
335
336 ret_val = readl( gpioreg );
337 ret_val |= SET_CLOCK_LO;
338 writel( ret_val, gpioreg);
339}
340
341//*****************************************************************
342//
343//
344// This routine will advance the clock by one period
345//
346//
347//*****************************************************************
348static void tl_i2c_clock_pulse( UCHAR value, void* GPIOout )
349{
350 ULONG ret_val;
351
352 // clear the clock bit
353 tl_clr_clock( GPIOout );
354
355 i2c_delay(0);
356
357
358 // read the port to preserve non-I2C bits
359 ret_val = readl( GPIOout );
360
361 // clear the data & clock bits
362 ret_val &= 0xFFFFFFf3;
363
364 // write the value passed in...
365 // data can only change while clock is LOW!
366 ret_val |= value; // the data
367 ret_val |= SET_CLOCK_LO; // the clock
368 writel( ret_val, GPIOout );
369
370 i2c_delay(0);
371
372
373 //set clock bit
374 tl_set_clock( GPIOout);
375}
376
377
378
379
380//*****************************************************************
381//
382//
383// This routine returns the 64-bit WWN
384//
385//
386//*****************************************************************
387int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf )
388{
389 ULONG len;
390 ULONG sub_len;
391 ULONG ptr_inc;
392 ULONG i;
393 ULONG j;
394 UCHAR *data_ptr;
395 UCHAR z;
396 UCHAR name;
397 UCHAR sub_name;
398 UCHAR done;
399 int iReturn=0; // def. 0 offset is failure to find WWN field
400
401
402
403 data_ptr = (UCHAR *)buf;
404
405 done = FALSE;
406 i = 0;
407
408 while ( (i < 128) && (!done) )
409 {
410 z = data_ptr[i];\
411 if ( !(z & 0x80) )
412 {
413 len = 1 + (z & 0x07);
414
415 name = (z & 0x78) >> 3;
416 if (name == 0x0F)
417 done = TRUE;
418 }
419 else
420 {
421 name = z & 0x7F;
422 len = 3 + data_ptr[i+1] + (data_ptr[i+2] << 8);
423
424 switch (name)
425 {
426 case 0x0D:
427 //
428 j = i + 3;
429 //
430 if ( data_ptr[j] == 0x3b ) {
431 len = 6;
432 break;
433 }
434
435 while ( j<(i+len) ) {
436 sub_name = (data_ptr[j] & 0x3f);
437 sub_len = data_ptr[j+1] +
438 (data_ptr[j+2] << 8);
439 ptr_inc = sub_len + 3;
440 switch (sub_name)
441 {
442 case 0x3C:
443 memcpy( wwnbuf, &data_ptr[j+3], 8);
444 iReturn = j+3;
445 break;
446 default:
447 break;
448 }
449 j += ptr_inc;
450 }
451 break;
452 default:
453 break;
454 }
455 }
456 //
457 i += len;
458 } // end while
459 return iReturn;
460}
461
462
463
464
465
466// define a short 5 micro sec delay, and longer (ms) delay
467
468static void i2c_delay(ULONG mstime)
469{
470 ULONG i;
471
472// NOTE: we only expect to use these delays when reading
473// our adapter's NVRAM, which happens only during adapter reset.
474// Delay technique from "Linux Device Drivers", A. Rubini
475// (1st Ed.) pg 137.
476
477// printk(" delay %lx ", mstime);
478 if( mstime ) // ms delay?
479 {
480 // delay technique
481 for( i=0; i < mstime; i++)
482 udelay(1000); // 1ms per loop
483
484 }
485 else // 5 micro sec delay
486
487 udelay( 5 ); // micro secs
488
489// printk("done\n");
490}
491
492
493
diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
deleted file mode 100644
index 3fda8d455c5b..000000000000
--- a/drivers/scsi/cpqfcTSinit.c
+++ /dev/null
@@ -1,2096 +0,0 @@
1/* Copyright(c) 2000, Compaq Computer Corporation
2 * Fibre Channel Host Bus Adapter
3 * 64-bit, 66MHz PCI
4 * Originally developed and tested on:
5 * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ...
6 * SP# P225CXCBFIEL6T, Rev XC
7 * SP# 161290-001, Rev XD
8 * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
13 * later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 * Written by Don Zimmerman
20 * IOCTL and procfs added by Jouke Numan
21 * SMP testing by Chel Van Gennip
22 *
23 * portions copied from:
24 * QLogic CPQFCTS SCSI-FCP
25 * Written by Erik H. Moe, ehm@cris.com
26 * Copyright 1995, Erik H. Moe
27 * Renamed and updated to 1.3.x by Michael Griffith <grif@cs.ucr.edu>
28 * Chris Loveland <cwl@iol.unh.edu> to support the isp2100 and isp2200
29*/
30
31
32#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
33
34#include <linux/config.h>
35#include <linux/interrupt.h>
36#include <linux/module.h>
37#include <linux/version.h>
38#include <linux/blkdev.h>
39#include <linux/kernel.h>
40#include <linux/string.h>
41#include <linux/types.h>
42#include <linux/pci.h>
43#include <linux/delay.h>
44#include <linux/timer.h>
45#include <linux/init.h>
46#include <linux/ioport.h> // request_region() prototype
47#include <linux/completion.h>
48
49#include <asm/io.h>
50#include <asm/uaccess.h> // ioctl related
51#include <asm/irq.h>
52#include <linux/spinlock.h>
53#include "scsi.h"
54#include <scsi/scsi_host.h>
55#include <scsi/scsi_ioctl.h>
56#include "cpqfcTSchip.h"
57#include "cpqfcTSstructs.h"
58#include "cpqfcTStrigger.h"
59
60#include "cpqfcTS.h"
61
62/* Embedded module documentation macros - see module.h */
63MODULE_AUTHOR("Compaq Computer Corporation");
64MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.5.4");
65MODULE_LICENSE("GPL");
66
67int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags);
68
69// This struct was originally defined in
70// /usr/src/linux/include/linux/proc_fs.h
71// since it's only partially implemented, we only use first
72// few fields...
73// NOTE: proc_fs changes in 2.4 kernel
74
75#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
76static struct proc_dir_entry proc_scsi_cpqfcTS =
77{
78 PROC_SCSI_CPQFCTS, // ushort low_ino (enumerated list)
79 7, // ushort namelen
80 DEV_NAME, // const char* name
81 S_IFDIR | S_IRUGO | S_IXUGO, // mode_t mode
82 2 // nlink_t nlink
83 // etc. ...
84};
85
86
87#endif
88
89#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
90# define CPQFC_DECLARE_COMPLETION(x) DECLARE_COMPLETION(x)
91# define CPQFC_WAITING waiting
92# define CPQFC_COMPLETE(x) complete(x)
93# define CPQFC_WAIT_FOR_COMPLETION(x) wait_for_completion(x);
94#else
95# define CPQFC_DECLARE_COMPLETION(x) DECLARE_MUTEX_LOCKED(x)
96# define CPQFC_WAITING sem
97# define CPQFC_COMPLETE(x) up(x)
98# define CPQFC_WAIT_FOR_COMPLETION(x) down(x)
99#endif
100
101static int cpqfc_alloc_private_data_pool(CPQFCHBA *hba);
102
103/* local function to load our per-HBA (local) data for chip
104 registers, FC link state, all FC exchanges, etc.
105
106 We allocate space and compute address offsets for the
107 most frequently accessed addresses; others (like World Wide
108 Name) are not necessary.
109*/
110static void Cpqfc_initHBAdata(CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev )
111{
112
113 cpqfcHBAdata->PciDev = PciDev; // copy PCI info ptr
114
115 // since x86 port space is 64k, we only need the lower 16 bits
116 cpqfcHBAdata->fcChip.Registers.IOBaseL =
117 PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
118
119 cpqfcHBAdata->fcChip.Registers.IOBaseU =
120 PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
121
122 // 32-bit memory addresses
123 cpqfcHBAdata->fcChip.Registers.MemBase =
124 PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
125
126 cpqfcHBAdata->fcChip.Registers.ReMapMemBase =
127 ioremap( PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK,
128 0x200);
129
130 cpqfcHBAdata->fcChip.Registers.RAMBase =
131 PciDev->resource[4].start;
132
133 cpqfcHBAdata->fcChip.Registers.SROMBase = // NULL for HP TS adapter
134 PciDev->resource[5].start;
135
136 // now the Tachlite chip registers
137 // the REGISTER struct holds both the physical address & last
138 // written value (some TL registers are WRITE ONLY)
139
140 cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address =
141 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX;
142
143 cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address =
144 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX;
145
146 // TL Frame Manager
147 cpqfcHBAdata->fcChip.Registers.FMconfig.address =
148 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONFIG;
149 cpqfcHBAdata->fcChip.Registers.FMcontrol.address =
150 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONTROL;
151 cpqfcHBAdata->fcChip.Registers.FMstatus.address =
152 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_STATUS;
153 cpqfcHBAdata->fcChip.Registers.FMLinkStatus1.address =
154 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT1;
155 cpqfcHBAdata->fcChip.Registers.FMLinkStatus2.address =
156 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT2;
157 cpqfcHBAdata->fcChip.Registers.FMBB_CreditZero.address =
158 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_BB_CREDIT0;
159
160 // TL Control Regs
161 cpqfcHBAdata->fcChip.Registers.TYconfig.address =
162 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONFIG;
163 cpqfcHBAdata->fcChip.Registers.TYcontrol.address =
164 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONTROL;
165 cpqfcHBAdata->fcChip.Registers.TYstatus.address =
166 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_STATUS;
167 cpqfcHBAdata->fcChip.Registers.rcv_al_pa.address =
168 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_RCV_AL_PA;
169 cpqfcHBAdata->fcChip.Registers.ed_tov.address =
170 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_ED_TOV;
171
172
173 cpqfcHBAdata->fcChip.Registers.INTEN.address =
174 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTEN;
175 cpqfcHBAdata->fcChip.Registers.INTPEND.address =
176 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTPEND;
177 cpqfcHBAdata->fcChip.Registers.INTSTAT.address =
178 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTSTAT;
179
180 DEBUG_PCI(printk(" cpqfcHBAdata->fcChip.Registers. :\n"));
181 DEBUG_PCI(printk(" IOBaseL = %x\n",
182 cpqfcHBAdata->fcChip.Registers.IOBaseL));
183 DEBUG_PCI(printk(" IOBaseU = %x\n",
184 cpqfcHBAdata->fcChip.Registers.IOBaseU));
185
186 /* printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase); */
187
188 DEBUG_PCI(printk(" SFQconsumerIndex.address = %p\n",
189 cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address));
190 DEBUG_PCI(printk(" ERQproducerIndex.address = %p\n",
191 cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address));
192 DEBUG_PCI(printk(" TYconfig.address = %p\n",
193 cpqfcHBAdata->fcChip.Registers.TYconfig.address));
194 DEBUG_PCI(printk(" FMconfig.address = %p\n",
195 cpqfcHBAdata->fcChip.Registers.FMconfig.address));
196 DEBUG_PCI(printk(" FMcontrol.address = %p\n",
197 cpqfcHBAdata->fcChip.Registers.FMcontrol.address));
198
199 // set default options for FC controller (chip)
200 cpqfcHBAdata->fcChip.Options.initiator = 1; // default: SCSI initiator
201 cpqfcHBAdata->fcChip.Options.target = 0; // default: SCSI target
202 cpqfcHBAdata->fcChip.Options.extLoopback = 0;// default: no loopback @GBIC
203 cpqfcHBAdata->fcChip.Options.intLoopback = 0;// default: no loopback inside chip
204
205 // set highest and lowest FC-PH version the adapter/driver supports
206 // (NOT strict compliance)
207 cpqfcHBAdata->fcChip.highest_FCPH_ver = FC_PH3;
208 cpqfcHBAdata->fcChip.lowest_FCPH_ver = FC_PH43;
209
210 // set function points for this controller / adapter
211 cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite;
212 cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite;
213 cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite;
214 cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues;
215 cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues;
216 cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite;
217 cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl;
218 cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry;
219 cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;
220 cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN;
221 cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM;
222
223 if (cpqfc_alloc_private_data_pool(cpqfcHBAdata) != 0) {
224 printk(KERN_WARNING
225 "cpqfc: unable to allocate pool for passthru ioctls. "
226 "Passthru ioctls disabled.\n");
227 }
228}
229
230
231/* (borrowed from linux/drivers/scsi/hosts.c) */
232static void launch_FCworker_thread(struct Scsi_Host *HostAdapter)
233{
234 DECLARE_MUTEX_LOCKED(sem);
235
236 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
237
238 ENTER("launch_FC_worker_thread");
239
240 cpqfcHBAdata->notify_wt = &sem;
241
242 /* must unlock before kernel_thread(), for it may cause a reschedule. */
243 spin_unlock_irq(HostAdapter->host_lock);
244 kernel_thread((int (*)(void *))cpqfcTSWorkerThread,
245 (void *) HostAdapter, 0);
246 /*
247 * Now wait for the kernel error thread to initialize itself
248
249 */
250 down (&sem);
251 spin_lock_irq(HostAdapter->host_lock);
252 cpqfcHBAdata->notify_wt = NULL;
253
254 LEAVE("launch_FC_worker_thread");
255
256}
257
258
259/* "Entry" point to discover if any supported PCI
260 bus adapter can be found
261*/
262/* We're supporting:
263 * Compaq 64-bit, 66MHz HBA with Tachyon TS
264 * Agilent XL2
265 * HP Tachyon
266 */
267#define HBA_TYPES 3
268
269#ifndef PCI_DEVICE_ID_COMPAQ_
270#define PCI_DEVICE_ID_COMPAQ_TACHYON 0xa0fc
271#endif
272
273static struct SupportedPCIcards cpqfc_boards[] __initdata = {
274 {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TACHYON},
275 {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHLITE},
276 {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHYON},
277};
278
279
280int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
281{
282 int NumberOfAdapters=0; // how many of our PCI adapters are found?
283 struct pci_dev *PciDev = NULL;
284 struct Scsi_Host *HostAdapter = NULL;
285 CPQFCHBA *cpqfcHBAdata = NULL;
286 struct timer_list *cpqfcTStimer = NULL;
287 int i;
288
289 ENTER("cpqfcTS_detect");
290
291#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
292 ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
293#else
294 ScsiHostTemplate->proc_name = "cpqfcTS";
295#endif
296
297 for( i=0; i < HBA_TYPES; i++)
298 {
299 // look for all HBAs of each type
300
301 while((PciDev = pci_find_device(cpqfc_boards[i].vendor_id,
302 cpqfc_boards[i].device_id, PciDev)))
303 {
304
305 if (pci_enable_device(PciDev)) {
306 printk(KERN_ERR
307 "cpqfc: can't enable PCI device at %s\n", pci_name(PciDev));
308 goto err_continue;
309 }
310
311 if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
312 printk(KERN_WARNING
313 "cpqfc: HBA cannot support required DMA mask, skipping.\n");
314 goto err_disable_dev;
315 }
316
317 // NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes...
318 /* printk(" scsi_register allocating %d bytes for FC HBA\n",
319 (ULONG)sizeof(CPQFCHBA)); */
320
321 HostAdapter = scsi_register( ScsiHostTemplate, sizeof( CPQFCHBA ) );
322
323 if(HostAdapter == NULL) {
324 printk(KERN_WARNING
325 "cpqfc: can't register SCSI HBA, skipping.\n");
326 goto err_disable_dev;
327 }
328 DEBUG_PCI( printk(" HBA found!\n"));
329 DEBUG_PCI( printk(" HostAdapter->PciDev->irq = %u\n", PciDev->irq) );
330 DEBUG_PCI(printk(" PciDev->baseaddress[0]= %lx\n",
331 PciDev->resource[0].start));
332 DEBUG_PCI(printk(" PciDev->baseaddress[1]= %lx\n",
333 PciDev->resource[1].start));
334 DEBUG_PCI(printk(" PciDev->baseaddress[2]= %lx\n",
335 PciDev->resource[2].start));
336 DEBUG_PCI(printk(" PciDev->baseaddress[3]= %lx\n",
337 PciDev->resource[3].start));
338
339 HostAdapter->irq = PciDev->irq; // copy for Scsi layers
340
341 // HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper),
342 // for a total I/O port address space of 512 bytes.
343 // mask out the I/O port address (lower) & record
344 HostAdapter->io_port = (unsigned int)
345 PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
346 HostAdapter->n_io_port = 0xff;
347
348 // i.e., expect 128 targets (arbitrary number), while the
349 // RA-4000 supports 32 LUNs
350 HostAdapter->max_id = 0; // incremented as devices log in
351 HostAdapter->max_lun = CPQFCTS_MAX_LUN; // LUNs per FC device
352 HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses?
353
354 // get the pointer to our HBA specific data... (one for
355 // each HBA on the PCI bus(ses)).
356 cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
357
358 // make certain our data struct is clear
359 memset( cpqfcHBAdata, 0, sizeof( CPQFCHBA ) );
360
361
362 // initialize our HBA info
363 cpqfcHBAdata->HBAnum = NumberOfAdapters;
364
365 cpqfcHBAdata->HostAdapter = HostAdapter; // back ptr
366 Cpqfc_initHBAdata( cpqfcHBAdata, PciDev ); // fill MOST fields
367
368 cpqfcHBAdata->HBAnum = NumberOfAdapters;
369 spin_lock_init(&cpqfcHBAdata->hba_spinlock);
370
371 // request necessary resources and check for conflicts
372 if( request_irq( HostAdapter->irq,
373 cpqfcTS_intr_handler,
374 SA_INTERRUPT | SA_SHIRQ,
375 DEV_NAME,
376 HostAdapter) )
377 {
378 printk(KERN_WARNING "cpqfc: IRQ %u already used\n", HostAdapter->irq);
379 goto err_unregister;
380 }
381
382 // Since we have two 256-byte I/O port ranges (upper
383 // and lower), check them both
384 if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseU,
385 0xff, DEV_NAME ) )
386 {
387 printk(KERN_WARNING "cpqfc: address in use: %x\n",
388 cpqfcHBAdata->fcChip.Registers.IOBaseU);
389 goto err_free_irq;
390 }
391
392 if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseL,
393 0xff, DEV_NAME ) )
394 {
395 printk(KERN_WARNING "cpqfc: address in use: %x\n",
396 cpqfcHBAdata->fcChip.Registers.IOBaseL);
397 goto err_release_region_U;
398 }
399
400 // OK, we have grabbed everything we need now.
401 DEBUG_PCI(printk(" Reserved 255 I/O addresses @ %x\n",
402 cpqfcHBAdata->fcChip.Registers.IOBaseL ));
403 DEBUG_PCI(printk(" Reserved 255 I/O addresses @ %x\n",
404 cpqfcHBAdata->fcChip.Registers.IOBaseU ));
405
406
407
408 // start our kernel worker thread
409
410 spin_lock_irq(HostAdapter->host_lock);
411 launch_FCworker_thread(HostAdapter);
412
413
414 // start our TimerTask...
415
416 cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer;
417
418 init_timer( cpqfcTStimer); // Linux clears next/prev values
419 cpqfcTStimer->expires = jiffies + HZ; // one second
420 cpqfcTStimer->data = (unsigned long)cpqfcHBAdata; // this adapter
421 cpqfcTStimer->function = cpqfcTSheartbeat; // handles timeouts, housekeeping
422
423 add_timer( cpqfcTStimer); // give it to Linux
424
425
426 // now initialize our hardware...
427 if (cpqfcHBAdata->fcChip.InitializeTachyon( cpqfcHBAdata, 1,1)) {
428 printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n");
429 goto err_release_region_L;
430 }
431
432 cpqfcHBAdata->fcStatsTime = jiffies; // (for FC Statistics delta)
433
434 // give our HBA time to initialize and login current devices...
435 {
436 // The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000,
437 // has the following algorithm for FL_Port startup:
438 // Time(sec) Action
439 // 0: Device Plugin and LIP(F7,F7) transmission
440 // 1.0 LIP incoming
441 // 1.027 LISA incoming, no CLS! (link not up)
442 // 1.028 NOS incoming (switch test for N_Port)
443 // 1.577 ED_TOV expired, transmit LIPs again
444 // 3.0 LIP(F8,F7) incoming (switch passes Tach Prim.Sig)
445 // 3.028 LILP received, link up, FLOGI starts
446 // slowest(worst) case, measured on 1Gb Finisar GT analyzer
447
448 unsigned long stop_time;
449
450 spin_unlock_irq(HostAdapter->host_lock);
451 stop_time = jiffies + 4*HZ;
452 while ( time_before(jiffies, stop_time) )
453 schedule(); // (our worker task needs to run)
454
455 }
456
457 spin_lock_irq(HostAdapter->host_lock);
458 NumberOfAdapters++;
459 spin_unlock_irq(HostAdapter->host_lock);
460
461 continue;
462
463err_release_region_L:
464 release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff );
465err_release_region_U:
466 release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff );
467err_free_irq:
468 free_irq( HostAdapter->irq, HostAdapter);
469err_unregister:
470 scsi_unregister( HostAdapter);
471err_disable_dev:
472 pci_disable_device( PciDev );
473err_continue:
474 continue;
475 } // end of while()
476 }
477
478 LEAVE("cpqfcTS_detect");
479
480 return NumberOfAdapters;
481}
482
483#ifdef SUPPORT_RESET
484static void my_ioctl_done (Scsi_Cmnd * SCpnt)
485{
486 struct request * req;
487
488 req = SCpnt->request;
489 req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
490
491 if (req->CPQFC_WAITING != NULL)
492 CPQFC_COMPLETE(req->CPQFC_WAITING);
493}
494#endif
495
496static int cpqfc_alloc_private_data_pool(CPQFCHBA *hba)
497{
498 hba->private_data_bits = NULL;
499 hba->private_data_pool = NULL;
500 hba->private_data_bits =
501 kmalloc(((CPQFC_MAX_PASSTHRU_CMDS+BITS_PER_LONG-1) /
502 BITS_PER_LONG)*sizeof(unsigned long),
503 GFP_KERNEL);
504 if (hba->private_data_bits == NULL)
505 return -1;
506 memset(hba->private_data_bits, 0,
507 ((CPQFC_MAX_PASSTHRU_CMDS+BITS_PER_LONG-1) /
508 BITS_PER_LONG)*sizeof(unsigned long));
509 hba->private_data_pool = kmalloc(sizeof(cpqfc_passthru_private_t) *
510 CPQFC_MAX_PASSTHRU_CMDS, GFP_KERNEL);
511 if (hba->private_data_pool == NULL) {
512 kfree(hba->private_data_bits);
513 hba->private_data_bits = NULL;
514 return -1;
515 }
516 return 0;
517}
518
519static void cpqfc_free_private_data_pool(CPQFCHBA *hba)
520{
521 kfree(hba->private_data_bits);
522 kfree(hba->private_data_pool);
523}
524
525int is_private_data_of_cpqfc(CPQFCHBA *hba, void *pointer)
526{
527 /* Is pointer within our private data pool?
528 We use Scsi_Request->upper_private_data (normally
529 reserved for upper layer drivers, e.g. the sg driver)
530 We check to see if the pointer is ours by looking at
531 its address. Is this ok? Hmm, it occurs to me that
532 a user app might do something bad by using sg to send
533 a cpqfc passthrough ioctl with upper_data_private
534 forged to be somewhere in our pool..., though they'd
535 normally have to be root already to do this. */
536
537 return (pointer != NULL &&
538 pointer >= (void *) hba->private_data_pool &&
539 pointer < (void *) hba->private_data_pool +
540 sizeof(*hba->private_data_pool) *
541 CPQFC_MAX_PASSTHRU_CMDS);
542}
543
544cpqfc_passthru_private_t *cpqfc_alloc_private_data(CPQFCHBA *hba)
545{
546 int i;
547
548 do {
549 i = find_first_zero_bit(hba->private_data_bits,
550 CPQFC_MAX_PASSTHRU_CMDS);
551 if (i == CPQFC_MAX_PASSTHRU_CMDS)
552 return NULL;
553 } while ( test_and_set_bit(i & (BITS_PER_LONG - 1),
554 hba->private_data_bits+(i/BITS_PER_LONG)) != 0);
555 return &hba->private_data_pool[i];
556}
557
558void cpqfc_free_private_data(CPQFCHBA *hba, cpqfc_passthru_private_t *data)
559{
560 int i;
561 i = data - hba->private_data_pool;
562 clear_bit(i&(BITS_PER_LONG-1),
563 hba->private_data_bits+(i/BITS_PER_LONG));
564}
565
566int cpqfcTS_ioctl( struct scsi_device *ScsiDev, int Cmnd, void *arg)
567{
568 int result = 0;
569 struct Scsi_Host *HostAdapter = ScsiDev->host;
570 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
571 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
572 PFC_LOGGEDIN_PORT pLoggedInPort = NULL;
573 struct scsi_cmnd *DumCmnd;
574 int i, j;
575 VENDOR_IOCTL_REQ ioc;
576 cpqfc_passthru_t *vendor_cmd;
577 Scsi_Device *SDpnt;
578 Scsi_Request *ScsiPassThruReq;
579 cpqfc_passthru_private_t *privatedata;
580
581 ENTER("cpqfcTS_ioctl ");
582
583 // printk("ioctl CMND %d", Cmnd);
584 switch (Cmnd) {
585 // Passthrough provides a mechanism to bypass the RAID
586 // or other controller and talk directly to the devices
587 // (e.g. physical disk drive)
588 // Passthrough commands, unfortunately, tend to be vendor
589 // specific; this is tailored to COMPAQ's RAID (RA4x00)
590 case CPQFCTS_SCSI_PASSTHRU:
591 {
592 void *buf = NULL; // for kernel space buffer for user data
593
594 /* Check that our pool got allocated ok. */
595 if (cpqfcHBAdata->private_data_pool == NULL)
596 return -ENOMEM;
597
598 if( !arg)
599 return -EINVAL;
600
601 // must be super user to send stuff directly to the
602 // controller and/or physical drives...
603 if( !capable(CAP_SYS_RAWIO) )
604 return -EPERM;
605
606 // copy the caller's struct to our space.
607 if( copy_from_user( &ioc, arg, sizeof( VENDOR_IOCTL_REQ)))
608 return( -EFAULT);
609
610 vendor_cmd = ioc.argp; // i.e., CPQ specific command struct
611
612 // If necessary, grab a kernel/DMA buffer
613 if( vendor_cmd->len)
614 {
615 buf = kmalloc( vendor_cmd->len, GFP_KERNEL);
616 if( !buf)
617 return -ENOMEM;
618 }
619 // Now build a Scsi_Request to pass down...
620 ScsiPassThruReq = scsi_allocate_request(ScsiDev, GFP_KERNEL);
621 if (ScsiPassThruReq == NULL) {
622 kfree(buf);
623 return -ENOMEM;
624 }
625 ScsiPassThruReq->upper_private_data =
626 cpqfc_alloc_private_data(cpqfcHBAdata);
627 if (ScsiPassThruReq->upper_private_data == NULL) {
628 kfree(buf);
629 scsi_release_request(ScsiPassThruReq); // "de-allocate"
630 return -ENOMEM;
631 }
632
633 if (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) {
634 if (vendor_cmd->len) { // Need data from user?
635 if (copy_from_user(buf, vendor_cmd->bufp,
636 vendor_cmd->len)) {
637 kfree(buf);
638 cpqfc_free_private_data(cpqfcHBAdata,
639 ScsiPassThruReq->upper_private_data);
640 scsi_release_request(ScsiPassThruReq);
641 return( -EFAULT);
642 }
643 }
644 ScsiPassThruReq->sr_data_direction = DMA_TO_DEVICE;
645 } else if (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) {
646 ScsiPassThruReq->sr_data_direction = DMA_FROM_DEVICE;
647 } else
648 // maybe this means a bug in the user app
649 ScsiPassThruReq->sr_data_direction = DMA_BIDIRECTIONAL;
650
651 ScsiPassThruReq->sr_cmd_len = 0; // set correctly by scsi_do_req()
652 ScsiPassThruReq->sr_sense_buffer[0] = 0;
653 ScsiPassThruReq->sr_sense_buffer[2] = 0;
654
655 // We copy the scheme used by sd.c:spinup_disk() to submit commands
656 // to our own HBA. We do this in order to stall the
657 // thread calling the IOCTL until it completes, and use
658 // the same "_quecommand" function for synchronizing
659 // FC Link events with our "worker thread".
660
661 privatedata = ScsiPassThruReq->upper_private_data;
662 privatedata->bus = vendor_cmd->bus;
663 privatedata->pdrive = vendor_cmd->pdrive;
664
665 // eventually gets us to our own _quecommand routine
666 scsi_wait_req(ScsiPassThruReq,
667 &vendor_cmd->cdb[0], buf, vendor_cmd->len,
668 10*HZ, // timeout
669 1); // retries
670 result = ScsiPassThruReq->sr_result;
671
672 // copy any sense data back to caller
673 if( result != 0 )
674 {
675 memcpy( vendor_cmd->sense_data, // see struct def - size=40
676 ScsiPassThruReq->sr_sense_buffer,
677 sizeof(ScsiPassThruReq->sr_sense_buffer) <
678 sizeof(vendor_cmd->sense_data) ?
679 sizeof(ScsiPassThruReq->sr_sense_buffer) :
680 sizeof(vendor_cmd->sense_data)
681 );
682 }
683 SDpnt = ScsiPassThruReq->sr_device;
684 /* upper_private_data is already freed in call_scsi_done() */
685 scsi_release_request(ScsiPassThruReq); // "de-allocate"
686 ScsiPassThruReq = NULL;
687
688 // need to pass data back to user (space)?
689 if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) &&
690 vendor_cmd->len )
691 if( copy_to_user( vendor_cmd->bufp, buf, vendor_cmd->len))
692 result = -EFAULT;
693
694 kfree(buf);
695
696 return result;
697 }
698
699 case CPQFCTS_GETPCIINFO:
700 {
701 cpqfc_pci_info_struct pciinfo;
702
703 if( !arg)
704 return -EINVAL;
705
706
707
708 pciinfo.bus = cpqfcHBAdata->PciDev->bus->number;
709 pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn;
710 pciinfo.board_id = cpqfcHBAdata->PciDev->device |
711 (cpqfcHBAdata->PciDev->vendor <<16);
712
713 if(copy_to_user( arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
714 return( -EFAULT);
715 return 0;
716 }
717
718 case CPQFCTS_GETDRIVVER:
719 {
720 DriverVer_type DriverVer =
721 CPQFCTS_DRIVER_VER( VER_MAJOR,VER_MINOR,VER_SUBMINOR);
722
723 if( !arg)
724 return -EINVAL;
725
726 if(copy_to_user( arg, &DriverVer, sizeof(DriverVer)))
727 return( -EFAULT);
728 return 0;
729 }
730
731
732
733 case CPQFC_IOCTL_FC_TARGET_ADDRESS:
734 // can we find an FC device mapping to this SCSI target?
735/* DumCmnd.channel = ScsiDev->channel; */ // For searching
736/* DumCmnd.target = ScsiDev->id; */
737/* DumCmnd.lun = ScsiDev->lun; */
738
739 DumCmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
740 if (!DumCmnd)
741 return -ENOMEM;
742
743 pLoggedInPort = fcFindLoggedInPort( fcChip,
744 DumCmnd, // search Scsi Nexus
745 0, // DON'T search linked list for FC port id
746 NULL, // DON'T search linked list for FC WWN
747 NULL); // DON'T care about end of list
748 scsi_put_command (DumCmnd);
749 if (pLoggedInPort == NULL) {
750 result = -ENXIO;
751 break;
752 }
753 result = access_ok(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress)) ? 0 : -EFAULT;
754 if (result) break;
755
756 put_user(pLoggedInPort->port_id,
757 &((Scsi_FCTargAddress *) arg)->host_port_id);
758
759 for( i=3,j=0; i>=0; i--) // copy the LOGIN port's WWN
760 put_user(pLoggedInPort->u.ucWWN[i],
761 &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
762 for( i=7; i>3; i--) // copy the LOGIN port's WWN
763 put_user(pLoggedInPort->u.ucWWN[i],
764 &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
765 break;
766
767
768 case CPQFC_IOCTL_FC_TDR:
769
770 result = cpqfcTS_TargetDeviceReset( ScsiDev, 0);
771
772 break;
773
774
775
776
777 default:
778 result = -EINVAL;
779 break;
780 }
781
782 LEAVE("cpqfcTS_ioctl");
783 return result;
784}
785
786
787/* "Release" the Host Bus Adapter...
788 disable interrupts, stop the HBA, release the interrupt,
789 and free all resources */
790
791int cpqfcTS_release(struct Scsi_Host *HostAdapter)
792{
793 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
794
795
796 ENTER("cpqfcTS_release");
797
798 DEBUG_PCI( printk(" cpqfcTS: delete timer...\n"));
799 del_timer( &cpqfcHBAdata->cpqfcTStimer);
800
801 // disable the hardware...
802 DEBUG_PCI( printk(" disable hardware, destroy queues, free mem\n"));
803 cpqfcHBAdata->fcChip.ResetTachyon( cpqfcHBAdata, CLEAR_FCPORTS);
804
805 // kill kernel thread
806 if( cpqfcHBAdata->worker_thread ) // (only if exists)
807 {
808 DECLARE_MUTEX_LOCKED(sem); // synchronize thread kill
809
810 cpqfcHBAdata->notify_wt = &sem;
811 DEBUG_PCI( printk(" killing kernel thread\n"));
812 send_sig( SIGKILL, cpqfcHBAdata->worker_thread, 1);
813 down( &sem);
814 cpqfcHBAdata->notify_wt = NULL;
815
816 }
817
818 cpqfc_free_private_data_pool(cpqfcHBAdata);
819 // free Linux resources
820 DEBUG_PCI( printk(" cpqfcTS: freeing resources...\n"));
821 free_irq( HostAdapter->irq, HostAdapter);
822 scsi_unregister( HostAdapter);
823 release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff);
824 release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff);
825 /* we get "vfree: bad address" executing this - need to investigate...
826 if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) !=
827 cpqfcHBAdata->fcChip.Registers.ReMapMemBase)
828 vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
829*/
830 pci_disable_device( cpqfcHBAdata->PciDev);
831
832 LEAVE("cpqfcTS_release");
833 return 0;
834}
835
836
837const char * cpqfcTS_info(struct Scsi_Host *HostAdapter)
838{
839 static char buf[300];
840 CPQFCHBA *cpqfcHBA;
841 int BusSpeed, BusWidth;
842
843 // get the pointer to our Scsi layer HBA buffer
844 cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
845
846 BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR &0x4) > 0 ?
847 64 : 32;
848
849 if( cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000)
850 BusSpeed = 66;
851 else
852 BusSpeed = 33;
853
854 sprintf(buf,
855"%s: WWN %08X%08X\n on PCI bus %d device 0x%02x irq %d IObaseL 0x%x, MEMBASE 0x%x\nPCI bus width %d bits, bus speed %d MHz\nFCP-SCSI Driver v%d.%d.%d",
856 cpqfcHBA->fcChip.Name,
857 cpqfcHBA->fcChip.Registers.wwn_hi,
858 cpqfcHBA->fcChip.Registers.wwn_lo,
859 cpqfcHBA->PciDev->bus->number,
860 cpqfcHBA->PciDev->device,
861 HostAdapter->irq,
862 cpqfcHBA->fcChip.Registers.IOBaseL,
863 cpqfcHBA->fcChip.Registers.MemBase,
864 BusWidth,
865 BusSpeed,
866 VER_MAJOR, VER_MINOR, VER_SUBMINOR
867);
868
869
870 cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
871 cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
872 return buf;
873}
874
875//
876// /proc/scsi support. The following routines allow us to do 'normal'
877// sprintf like calls to return the currently requested piece (buflenght
878// chars, starting at bufoffset) of the file. Although procfs allows for
879// a 1 Kb bytes overflow after te supplied buffer, I consider it bad
880// programming to use it to make programming a little simpler. This piece
881// of coding is borrowed from ncr53c8xx.c with some modifications
882//
883struct info_str
884{
885 char *buffer; // Pointer to output buffer
886 int buflength; // It's length
887 int bufoffset; // File offset corresponding with buf[0]
888 int buffillen; // Current filled length
889 int filpos; // Current file offset
890};
891
892static void copy_mem_info(struct info_str *info, char *data, int datalen)
893{
894
895 if (info->filpos < info->bufoffset) { // Current offset before buffer offset
896 if (info->filpos + datalen <= info->bufoffset) {
897 info->filpos += datalen; // Discard if completely before buffer
898 return;
899 } else { // Partial copy, set to begin
900 data += (info->bufoffset - info->filpos);
901 datalen -= (info->bufoffset - info->filpos);
902 info->filpos = info->bufoffset;
903 }
904 }
905
906 info->filpos += datalen; // Update current offset
907
908 if (info->buffillen == info->buflength) // Buffer full, discard
909 return;
910
911 if (info->buflength - info->buffillen < datalen) // Overflows buffer ?
912 datalen = info->buflength - info->buffillen;
913
914 memcpy(info->buffer + info->buffillen, data, datalen);
915 info->buffillen += datalen;
916}
917
918static int copy_info(struct info_str *info, char *fmt, ...)
919{
920 va_list args;
921 char buf[400];
922 int len;
923
924 va_start(args, fmt);
925 len = vsprintf(buf, fmt, args);
926 va_end(args);
927
928 copy_mem_info(info, buf, len);
929 return len;
930}
931
932
933// Routine to get data for /proc RAM filesystem
934//
935int cpqfcTS_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length,
936 int inout)
937{
938 struct scsi_cmnd *DumCmnd;
939 struct scsi_device *ScsiDev;
940 int Chan, Targ, i;
941 struct info_str info;
942 CPQFCHBA *cpqfcHBA;
943 PTACHYON fcChip;
944 PFC_LOGGEDIN_PORT pLoggedInPort;
945 char buf[81];
946
947 if (inout) return -EINVAL;
948
949 // get the pointer to our Scsi layer HBA buffer
950 cpqfcHBA = (CPQFCHBA *)host->hostdata;
951 fcChip = &cpqfcHBA->fcChip;
952
953 *start = buffer;
954
955 info.buffer = buffer;
956 info.buflength = length;
957 info.bufoffset = offset;
958 info.filpos = 0;
959 info.buffillen = 0;
960 copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR);
961 cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[0]);
962 cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
963 copy_info(&info, "%s\n", buf);
964
965#define DISPLAY_WWN_INFO
966#ifdef DISPLAY_WWN_INFO
967 ScsiDev = scsi_get_host_dev (host);
968 if (!ScsiDev)
969 return -ENOMEM;
970 DumCmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
971 if (!DumCmnd) {
972 scsi_free_host_dev (ScsiDev);
973 return -ENOMEM;
974 }
975 copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n");
976 for ( Chan=0; Chan <= host->max_channel; Chan++) {
977 DumCmnd->device->channel = Chan;
978 for (Targ=0; Targ <= host->max_id; Targ++) {
979 DumCmnd->device->id = Targ;
980 if ((pLoggedInPort = fcFindLoggedInPort( fcChip,
981 DumCmnd, // search Scsi Nexus
982 0, // DON'T search list for FC port id
983 NULL, // DON'T search list for FC WWN
984 NULL))){ // DON'T care about end of list
985 copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ",
986 host->host_no, Chan, Targ);
987 for( i=3; i>=0; i--) // copy the LOGIN port's WWN
988 copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
989 for( i=7; i>3; i--) // copy the LOGIN port's WWN
990 copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
991 copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id);
992 }
993 }
994 }
995
996 scsi_put_command (DumCmnd);
997 scsi_free_host_dev (ScsiDev);
998#endif
999
1000
1001
1002
1003
1004// Unfortunately, the proc_info buffer isn't big enough
1005// for everything we would like...
1006// For FC stats, compile this and turn off WWN stuff above
1007//#define DISPLAY_FC_STATS
1008#ifdef DISPLAY_FC_STATS
1009// get the Fibre Channel statistics
1010 {
1011 int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ;
1012 int days,hours,minutes,secs;
1013
1014 days = DeltaSecs / (3600*24); // days
1015 hours = (DeltaSecs% (3600*24)) / 3600; // hours
1016 minutes = (DeltaSecs%3600 /60); // minutes
1017 secs = DeltaSecs%60; // secs
1018copy_info( &info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n",
1019 days, hours, minutes, secs);
1020 }
1021
1022 cpqfcHBA->fcStatsTime = jiffies; // (for next delta)
1023
1024 copy_info( &info, " LinkUp %9u LinkDown %u\n",
1025 fcChip->fcStats.linkUp, fcChip->fcStats.linkDown);
1026
1027 copy_info( &info, " Loss of Signal %9u Loss of Sync %u\n",
1028 fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync);
1029
1030 copy_info( &info, " Discarded Frames %9u Bad CRC Frame %u\n",
1031 fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC);
1032
1033 copy_info( &info, " TACH LinkFailTX %9u TACH LinkFailRX %u\n",
1034 fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX);
1035
1036 copy_info( &info, " TACH RxEOFa %9u TACH Elastic Store %u\n",
1037 fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores);
1038
1039 copy_info( &info, " BufferCreditWait %9uus TACH FM Inits %u\n",
1040 fcChip->fcStats.BB0_Timer*10, fcChip->fcStats.FMinits );
1041
1042 copy_info( &info, " FC-2 Timeouts %9u FC-2 Logouts %u\n",
1043 fcChip->fcStats.timeouts, fcChip->fcStats.logouts);
1044
1045 copy_info( &info, " FC-2 Aborts %9u FC-4 Aborts %u\n",
1046 fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted);
1047
1048 // clear the counters
1049 cpqfcTSClearLinkStatusCounters( fcChip);
1050#endif
1051
1052 return info.buffillen;
1053}
1054
1055
1056#if DEBUG_CMND
1057
1058UCHAR *ScsiToAscii( UCHAR ScsiCommand)
1059{
1060
1061/*++
1062
1063Routine Description:
1064
1065 Converts a SCSI command to a text string for debugging purposes.
1066
1067
1068Arguments:
1069
1070 ScsiCommand -- hex value SCSI Command
1071
1072
1073Return Value:
1074
1075 An ASCII, null-terminated string if found, else returns NULL.
1076
1077Original code from M. McGowen, Compaq
1078--*/
1079
1080
1081 switch (ScsiCommand)
1082 {
1083 case 0x00:
1084 return( "Test Unit Ready" );
1085
1086 case 0x01:
1087 return( "Rezero Unit or Rewind" );
1088
1089 case 0x02:
1090 return( "Request Block Address" );
1091
1092 case 0x03:
1093 return( "Requese Sense" );
1094
1095 case 0x04:
1096 return( "Format Unit" );
1097
1098 case 0x05:
1099 return( "Read Block Limits" );
1100
1101 case 0x07:
1102 return( "Reassign Blocks" );
1103
1104 case 0x08:
1105 return( "Read (6)" );
1106
1107 case 0x0a:
1108 return( "Write (6)" );
1109
1110 case 0x0b:
1111 return( "Seek (6)" );
1112
1113 case 0x12:
1114 return( "Inquiry" );
1115
1116 case 0x15:
1117 return( "Mode Select (6)" );
1118
1119 case 0x16:
1120 return( "Reserve" );
1121
1122 case 0x17:
1123 return( "Release" );
1124
1125 case 0x1a:
1126 return( "ModeSen(6)" );
1127
1128 case 0x1b:
1129 return( "Start/Stop Unit" );
1130
1131 case 0x1c:
1132 return( "Receive Diagnostic Results" );
1133
1134 case 0x1d:
1135 return( "Send Diagnostic" );
1136
1137 case 0x25:
1138 return( "Read Capacity" );
1139
1140 case 0x28:
1141 return( "Read (10)" );
1142
1143 case 0x2a:
1144 return( "Write (10)" );
1145
1146 case 0x2b:
1147 return( "Seek (10)" );
1148
1149 case 0x2e:
1150 return( "Write and Verify" );
1151
1152 case 0x2f:
1153 return( "Verify" );
1154
1155 case 0x34:
1156 return( "Pre-Fetch" );
1157
1158 case 0x35:
1159 return( "Synchronize Cache" );
1160
1161 case 0x37:
1162 return( "Read Defect Data (10)" );
1163
1164 case 0x3b:
1165 return( "Write Buffer" );
1166
1167 case 0x3c:
1168 return( "Read Buffer" );
1169
1170 case 0x3e:
1171 return( "Read Long" );
1172
1173 case 0x3f:
1174 return( "Write Long" );
1175
1176 case 0x41:
1177 return( "Write Same" );
1178
1179 case 0x4c:
1180 return( "Log Select" );
1181
1182 case 0x4d:
1183 return( "Log Sense" );
1184
1185 case 0x56:
1186 return( "Reserve (10)" );
1187
1188 case 0x57:
1189 return( "Release (10)" );
1190
1191 case 0xa0:
1192 return( "ReportLuns" );
1193
1194 case 0xb7:
1195 return( "Read Defect Data (12)" );
1196
1197 case 0xca:
1198 return( "Peripheral Device Addressing SCSI Passthrough" );
1199
1200 case 0xcb:
1201 return( "Compaq Array Firmware Passthrough" );
1202
1203 default:
1204 return( NULL );
1205 }
1206
1207} // end ScsiToAscii()
1208
1209void cpqfcTS_print_scsi_cmd(Scsi_Cmnd * cmd)
1210{
1211
1212printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n",
1213 ScsiToAscii( cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);
1214
1215if( cmd->cmnd[0] == 0) // Test Unit Ready?
1216{
1217 int i;
1218
1219 printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n",
1220 cmd->request_bufflen, cmd->use_sg, cmd->bufflen);
1221 printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n",
1222 cmd->request_buffer, cmd->sglist_len, cmd->buffer);
1223 for (i = 0; i < cmd->cmd_len; i++)
1224 printk("0x%02x ", cmd->cmnd[i]);
1225 printk("\n");
1226}
1227
1228}
1229
1230#endif /* DEBUG_CMND */
1231
1232
1233
1234
1235static void QueCmndOnBoardLock( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
1236{
1237 int i;
1238
1239 for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
1240 { // find spare slot
1241 if( cpqfcHBAdata->BoardLockCmnd[i] == NULL )
1242 {
1243 cpqfcHBAdata->BoardLockCmnd[i] = Cmnd;
1244// printk(" BoardLockCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
1245// i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
1246 break;
1247 }
1248 }
1249 if( i >= CPQFCTS_REQ_QUEUE_LEN)
1250 {
1251 printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd);
1252 }
1253
1254}
1255
1256
1257static void QueLinkDownCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
1258{
1259 int indx;
1260
1261 // Remember the command ptr so we can return; we'll complete when
1262 // the device comes back, causing immediate retry
1263 for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)//, SCptr++)
1264 {
1265 if( cpqfcHBAdata->LinkDnCmnd[indx] == NULL ) // available?
1266 {
1267#ifdef DUMMYCMND_DBG
1268 printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd,indx);
1269#endif
1270 cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd;
1271 break;
1272 }
1273 }
1274
1275 if( indx >= CPQFCTS_REQ_QUEUE_LEN ) // no space for Cmnd??
1276 {
1277 // this will result in an _abort call later (with possible trouble)
1278 printk("no buffer for LinkDnCmnd!! %p\n", Cmnd);
1279 }
1280}
1281
1282
1283
1284
1285
1286// The file <scsi/scsi_host.h> says not to call scsi_done from
1287// inside _queuecommand, so we'll do it from the heartbeat timer
1288// (clarification: Turns out it's ok to call scsi_done from queuecommand
1289// for cases that don't go to the hardware like scsi cmds destined
1290// for LUNs we know don't exist, so this code might be simplified...)
1291
1292static void QueBadTargetCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
1293{
1294 int i;
1295 // printk(" can't find target %d\n", Cmnd->target);
1296
1297 for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
1298 { // find spare slot
1299 if( cpqfcHBAdata->BadTargetCmnd[i] == NULL )
1300 {
1301 cpqfcHBAdata->BadTargetCmnd[i] = Cmnd;
1302// printk(" BadTargetCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
1303// i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
1304 break;
1305 }
1306 }
1307}
1308
1309
1310// This is the "main" entry point for Linux Scsi commands --
1311// it all starts here.
1312
1313int cpqfcTS_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *))
1314{
1315 struct Scsi_Host *HostAdapter = Cmnd->device->host;
1316 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
1317 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1318 TachFCHDR_GCMND fchs; // only use for FC destination id field
1319 PFC_LOGGEDIN_PORT pLoggedInPort;
1320 ULONG ulStatus, SESTtype;
1321 LONG ExchangeID;
1322
1323
1324
1325
1326 ENTER("cpqfcTS_queuecommand");
1327
1328 PCI_TRACEO( (ULONG)Cmnd, 0x98)
1329
1330
1331 Cmnd->scsi_done = done;
1332#ifdef DEBUG_CMND
1333 cpqfcTS_print_scsi_cmd( Cmnd);
1334#endif
1335
1336 // prevent board contention with kernel thread...
1337
1338 if( cpqfcHBAdata->BoardLock )
1339 {
1340// printk(" @BrdLck Hld@ ");
1341 QueCmndOnBoardLock( cpqfcHBAdata, Cmnd);
1342 }
1343
1344 else
1345 {
1346
1347 // in the current system (2.2.12), this routine is called
1348 // after spin_lock_irqsave(), so INTs are disabled. However,
1349 // we might have something pending in the LinkQ, which
1350 // might cause the WorkerTask to run. In case that
1351 // happens, make sure we lock it out.
1352
1353
1354
1355 PCI_TRACE( 0x98)
1356 CPQ_SPINLOCK_HBA( cpqfcHBAdata)
1357 PCI_TRACE( 0x98)
1358
1359 // can we find an FC device mapping to this SCSI target?
1360 pLoggedInPort = fcFindLoggedInPort( fcChip,
1361 Cmnd, // search Scsi Nexus
1362 0, // DON'T search linked list for FC port id
1363 NULL, // DON'T search linked list for FC WWN
1364 NULL); // DON'T care about end of list
1365
1366 if( pLoggedInPort == NULL ) // not found!
1367 {
1368// printk(" @Q bad targ cmnd %p@ ", Cmnd);
1369 QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
1370 }
1371 else if (Cmnd->device->lun >= CPQFCTS_MAX_LUN)
1372 {
1373 printk(KERN_WARNING "cpqfc: Invalid LUN: %d\n", Cmnd->device->lun);
1374 QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
1375 }
1376
1377 else // we know what FC device to send to...
1378 {
1379
1380 // does this device support FCP target functions?
1381 // (determined by PRLI field)
1382
1383 if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
1384 {
1385 printk(" Doesn't support TARGET functions port_id %Xh\n",
1386 pLoggedInPort->port_id );
1387 QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
1388 }
1389
1390 // In this case (previous login OK), the device is temporarily
1391 // unavailable waiting for re-login, in which case we expect it
1392 // to be back in between 25 - 500ms.
1393 // If the FC port doesn't log back in within several seconds
1394 // (i.e. implicit "logout"), or we get an explicit logout,
1395 // we set "device_blocked" in Scsi_Device struct; in this
1396 // case 30 seconds will elapse before Linux/Scsi sends another
1397 // command to the device.
1398 else if( pLoggedInPort->prli != TRUE )
1399 {
1400// printk("Device (Chnl/Target %d/%d) invalid PRLI, port_id %06lXh\n",
1401// Cmnd->channel, Cmnd->target, pLoggedInPort->port_id);
1402 QueLinkDownCmnd( cpqfcHBAdata, Cmnd);
1403// Need to use "blocked" flag??
1404// Cmnd->device->device_blocked = TRUE; // just let it timeout
1405 }
1406 else // device supports TARGET functions, and is logged in...
1407 {
1408 // (context of fchs is to "reply" to...)
1409 fchs.s_id = pLoggedInPort->port_id; // destination FC address
1410
1411 // what is the data direction? For data TO the device,
1412 // we need IWE (Intiator Write Entry). Otherwise, IRE.
1413
1414 if( Cmnd->cmnd[0] == WRITE_10 ||
1415 Cmnd->cmnd[0] == WRITE_6 ||
1416 Cmnd->cmnd[0] == WRITE_BUFFER ||
1417 Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE || // CPQ specific
1418 Cmnd->cmnd[0] == MODE_SELECT )
1419 {
1420 SESTtype = SCSI_IWE; // data from HBA to Device
1421 }
1422 else
1423 SESTtype = SCSI_IRE; // data from Device to HBA
1424
1425 ulStatus = cpqfcTSBuildExchange(
1426 cpqfcHBAdata,
1427 SESTtype, // e.g. Initiator Read Entry (IRE)
1428 &fchs, // we are originator; only use d_id
1429 Cmnd, // Linux SCSI command (with scatter/gather list)
1430 &ExchangeID );// fcController->fcExchanges index, -1 if failed
1431
1432 if( !ulStatus ) // Exchange setup?
1433
1434 {
1435 if( cpqfcHBAdata->BoardLock )
1436 {
1437 TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
1438 printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID);
1439 }
1440
1441 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
1442 if( !ulStatus )
1443 {
1444 PCI_TRACEO( ExchangeID, 0xB8)
1445 // submitted to Tach's Outbound Que (ERQ PI incremented)
1446 // waited for completion for ELS type (Login frames issued
1447 // synchronously)
1448 }
1449 else
1450 // check reason for Exchange not being started - we might
1451 // want to Queue and start later, or fail with error
1452 {
1453 printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus );
1454 }
1455 } // end good BuildExchange status
1456
1457 else // SEST table probably full -- why? hardware hang?
1458 {
1459 printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus);
1460 }
1461 } // end can't do FCP-SCSI target functions
1462 } // end can't find target (FC device)
1463
1464 CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
1465 }
1466
1467 PCI_TRACEO( (ULONG)Cmnd, 0x9C)
1468 LEAVE("cpqfcTS_queuecommand");
1469 return 0;
1470}
1471
1472
1473// Entry point for upper Scsi layer intiated abort. Typically
1474// this is called if the command (for hard disk) fails to complete
1475// in 30 seconds. This driver intends to complete all disk commands
1476// within Exchange ".timeOut" seconds (now 7) with target status, or
1477// in case of ".timeOut" expiration, a DID_SOFT_ERROR which causes
1478// immediate retry.
1479// If any disk commands get the _abort call, except for the case that
1480// the physical device was removed or unavailable due to hardware
1481// errors, it should be considered a driver error and reported to
1482// the author.
1483
1484int cpqfcTS_abort(Scsi_Cmnd *Cmnd)
1485{
1486// printk(" cpqfcTS_abort called?? \n");
1487 return 0;
1488}
1489
1490int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd)
1491{
1492
1493 struct Scsi_Host *HostAdapter = Cmnd->device->host;
1494 // get the pointer to our Scsi layer HBA buffer
1495 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
1496 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1497 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1498 int i;
1499 ENTER("cpqfcTS_eh_abort");
1500
1501 Cmnd->result = DID_ABORT <<16; // assume we'll find it
1502
1503 printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd);
1504 // See if we can find a Cmnd pointer that matches...
1505 // The most likely case is we accepted the command
1506 // from Linux Scsi (e.g. ceated a SEST entry) and it
1507 // got lost somehow. If we can't find any reference
1508 // to the passed pointer, we can only presume it
1509 // got completed as far as our driver is concerned.
1510 // If we found it, we will try to abort it through
1511 // common mechanism. If FC ABTS is successful (ACC)
1512 // or is rejected (RJT) by target, we will call
1513 // Scsi "done" quickly. Otherwise, the ABTS will timeout
1514 // and we'll call "done" later.
1515
1516 // Search the SEST exchanges for a matching Cmnd ptr.
1517 for( i=0; i< TACH_SEST_LEN; i++)
1518 {
1519 if( Exchanges->fcExchange[i].Cmnd == Cmnd )
1520 {
1521
1522 // found it!
1523 printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type);
1524
1525 Exchanges->fcExchange[i].status = INITIATOR_ABORT; // seconds default
1526 Exchanges->fcExchange[i].timeOut = 10; // seconds default (changed later)
1527
1528 // Since we need to immediately return the aborted Cmnd to Scsi
1529 // upper layers, we can't make future reference to any of its
1530 // fields (e.g the Nexus).
1531
1532 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i);
1533
1534 break;
1535 }
1536 }
1537
1538 if( i >= TACH_SEST_LEN ) // didn't find Cmnd ptr in chip's SEST?
1539 {
1540 // now search our non-SEST buffers (i.e. Cmnd waiting to
1541 // start on the HBA or waiting to complete with error for retry).
1542
1543 // first check BadTargetCmnd
1544 for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
1545 {
1546 if( cpqfcHBAdata->BadTargetCmnd[i] == Cmnd )
1547 {
1548 cpqfcHBAdata->BadTargetCmnd[i] = NULL;
1549 printk("in BadTargetCmnd Q\n");
1550 goto Done; // exit
1551 }
1552 }
1553
1554 // if not found above...
1555
1556 for( i=0; i < CPQFCTS_REQ_QUEUE_LEN; i++)
1557 {
1558 if( cpqfcHBAdata->LinkDnCmnd[i] == Cmnd )
1559 {
1560 cpqfcHBAdata->LinkDnCmnd[i] = NULL;
1561 printk("in LinkDnCmnd Q\n");
1562 goto Done;
1563 }
1564 }
1565
1566
1567 for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
1568 { // find spare slot
1569 if( cpqfcHBAdata->BoardLockCmnd[i] == Cmnd )
1570 {
1571 cpqfcHBAdata->BoardLockCmnd[i] = NULL;
1572 printk("in BoardLockCmnd Q\n");
1573 goto Done;
1574 }
1575 }
1576
1577 Cmnd->result = DID_ERROR <<16; // Hmmm...
1578 printk("Not found! ");
1579// panic("_abort");
1580 }
1581
1582Done:
1583
1584// panic("_abort");
1585 LEAVE("cpqfcTS_eh_abort");
1586 return 0; // (see scsi.h)
1587}
1588
1589
1590// FCP-SCSI Target Device Reset
1591// See dpANS Fibre Channel Protocol for SCSI
1592// X3.269-199X revision 12, pg 25
1593
1594#ifdef SUPPORT_RESET
1595
1596int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev,
1597 unsigned int reset_flags)
1598{
1599 int timeout = 10*HZ;
1600 int retries = 1;
1601 char scsi_cdb[12];
1602 int result;
1603 Scsi_Cmnd * SCpnt;
1604 Scsi_Device * SDpnt;
1605
1606// FIXME, cpqfcTS_TargetDeviceReset needs to be fixed
1607// similarly to how the passthrough ioctl was fixed
1608// around the 2.5.30 kernel. Scsi_Cmnd replaced with
1609// Scsi_Request, etc.
1610// For now, so people don't fall into a hole...
1611
1612 // printk(" ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
1613
1614 if (ScsiDev->host->eh_active) return FAILED;
1615
1616 memset( scsi_cdb, 0, sizeof( scsi_cdb));
1617
1618 scsi_cdb[0] = RELEASE;
1619
1620 SCpnt = scsi_get_command(ScsiDev, GFP_KERNEL);
1621 {
1622 CPQFC_DECLARE_COMPLETION(wait);
1623
1624 SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
1625
1626 // FIXME: this would panic, SCpnt->request would be NULL.
1627 SCpnt->request->CPQFC_WAITING = &wait;
1628 scsi_do_cmd(SCpnt, scsi_cdb, NULL, 0, my_ioctl_done, timeout, retries);
1629 CPQFC_WAIT_FOR_COMPLETION(&wait);
1630 SCpnt->request->CPQFC_WAITING = NULL;
1631 }
1632
1633
1634 if(driver_byte(SCpnt->result) != 0)
1635 switch(SCpnt->sense_buffer[2] & 0xf) {
1636 case ILLEGAL_REQUEST:
1637 if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
1638 else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
1639 break;
1640 case NOT_READY: // This happens if there is no disc in drive
1641 if(dev->removable && (cmd[0] != TEST_UNIT_READY)){
1642 printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n");
1643 break;
1644 }
1645 case UNIT_ATTENTION:
1646 if (dev->removable){
1647 dev->changed = 1;
1648 SCpnt->result = 0; // This is no longer considered an error
1649 // gag this error, VFS will log it anyway /axboe
1650 // printk(KERN_INFO "Disc change detected.\n");
1651 break;
1652 };
1653 default: // Fall through for non-removable media
1654 printk("SCSI error: host %d id %d lun %d return code = %x\n",
1655 dev->host->host_no,
1656 dev->id,
1657 dev->lun,
1658 SCpnt->result);
1659 printk("\tSense class %x, sense error %x, extended sense %x\n",
1660 sense_class(SCpnt->sense_buffer[0]),
1661 sense_error(SCpnt->sense_buffer[0]),
1662 SCpnt->sense_buffer[2] & 0xf);
1663
1664 };
1665 result = SCpnt->result;
1666
1667 SDpnt = SCpnt->device;
1668 scsi_put_command(SCpnt);
1669 SCpnt = NULL;
1670
1671 // printk(" LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
1672 return SUCCESS;
1673}
1674
1675#else
1676int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev,
1677 unsigned int reset_flags)
1678{
1679 return -ENOTSUPP;
1680}
1681
1682#endif /* SUPPORT_RESET */
1683
1684int cpqfcTS_eh_device_reset(Scsi_Cmnd *Cmnd)
1685{
1686 int retval;
1687 Scsi_Device *SDpnt = Cmnd->device;
1688 // printk(" ENTERING cpqfcTS_eh_device_reset() \n");
1689 spin_unlock_irq(Cmnd->device->host->host_lock);
1690 retval = cpqfcTS_TargetDeviceReset( SDpnt, 0);
1691 spin_lock_irq(Cmnd->device->host->host_lock);
1692 return retval;
1693}
1694
1695
1696int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
1697{
1698
1699 ENTER("cpqfcTS_reset");
1700
1701 LEAVE("cpqfcTS_reset");
1702 return SCSI_RESET_ERROR; /* Bus Reset Not supported */
1703}
1704
1705/* This function determines the bios parameters for a given
1706 harddisk. These tend to be numbers that are made up by the
1707 host adapter. Parameters:
1708 size, device number, list (heads, sectors,cylinders).
1709 (from hosts.h)
1710*/
1711
1712int cpqfcTS_biosparam(struct scsi_device *sdev, struct block_device *n,
1713 sector_t capacity, int ip[])
1714{
1715 int size = capacity;
1716
1717 ENTER("cpqfcTS_biosparam");
1718 ip[0] = 64;
1719 ip[1] = 32;
1720 ip[2] = size >> 11;
1721
1722 if( ip[2] > 1024 )
1723 {
1724 ip[0] = 255;
1725 ip[1] = 63;
1726 ip[2] = size / (ip[0] * ip[1]);
1727 }
1728
1729 LEAVE("cpqfcTS_biosparam");
1730 return 0;
1731}
1732
1733
1734
1735irqreturn_t cpqfcTS_intr_handler( int irq,
1736 void *dev_id,
1737 struct pt_regs *regs)
1738{
1739
1740 unsigned long flags, InfLoopBrk=0;
1741 struct Scsi_Host *HostAdapter = dev_id;
1742 CPQFCHBA *cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
1743 int MoreMessages = 1; // assume we have something to do
1744 UCHAR IntPending;
1745 int handled = 0;
1746
1747 ENTER("intr_handler");
1748 spin_lock_irqsave( HostAdapter->host_lock, flags);
1749 // is this our INT?
1750 IntPending = readb( cpqfcHBA->fcChip.Registers.INTPEND.address);
1751
1752 // broken boards can generate messages forever, so
1753 // prevent the infinite loop
1754#define INFINITE_IMQ_BREAK 10000
1755 if( IntPending )
1756 {
1757 handled = 1;
1758 // mask our HBA interrupts until we handle it...
1759 writeb( 0, cpqfcHBA->fcChip.Registers.INTEN.address);
1760
1761 if( IntPending & 0x4) // "INT" - Tach wrote to IMQ
1762 {
1763 while( (++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages ==1) )
1764 {
1765 MoreMessages = CpqTsProcessIMQEntry( HostAdapter); // ret 0 when done
1766 }
1767 if( InfLoopBrk >= INFINITE_IMQ_BREAK )
1768 {
1769 printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n");
1770 printk("or investigate alternate causes (e.g. physical FC layer)\n");
1771 }
1772
1773 else // working normally - re-enable INTs and continue
1774 writeb( 0x1F, cpqfcHBA->fcChip.Registers.INTEN.address);
1775
1776 } // (...ProcessIMQEntry() clears INT by writing IMQ consumer)
1777 else // indications of errors or problems...
1778 // these usually indicate critical system hardware problems.
1779 {
1780 if( IntPending & 0x10 )
1781 printk(" cpqfcTS adapter external memory parity error detected\n");
1782 if( IntPending & 0x8 )
1783 printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n");
1784 if( IntPending & 0x2 )
1785 printk(" cpqfcTS adapter DMA error detected\n");
1786 if( IntPending & 0x1 ) {
1787 UCHAR IntStat;
1788 printk(" cpqfcTS adapter PCI error detected\n");
1789 IntStat = readb( cpqfcHBA->fcChip.Registers.INTSTAT.address);
1790 printk("cpqfc: ISR = 0x%02x\n", IntStat);
1791 if (IntStat & 0x1) {
1792 __u16 pcistat;
1793 /* read the pci status register */
1794 pci_read_config_word(cpqfcHBA->PciDev, 0x06, &pcistat);
1795 printk("PCI status register is 0x%04x\n", pcistat);
1796 if (pcistat & 0x8000) printk("Parity Error Detected.\n");
1797 if (pcistat & 0x4000) printk("Signalled System Error\n");
1798 if (pcistat & 0x2000) printk("Received Master Abort\n");
1799 if (pcistat & 0x1000) printk("Received Target Abort\n");
1800 if (pcistat & 0x0800) printk("Signalled Target Abort\n");
1801 }
1802 if (IntStat & 0x4) printk("(INT)\n");
1803 if (IntStat & 0x8)
1804 printk("CRS: PCI master address crossed 46 bit bouandary\n");
1805 if (IntStat & 0x10) printk("MRE: external memory parity error.\n");
1806 }
1807 }
1808 }
1809 spin_unlock_irqrestore( HostAdapter->host_lock, flags);
1810 LEAVE("intr_handler");
1811 return IRQ_RETVAL(handled);
1812}
1813
1814
1815
1816
1817int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[])
1818{
1819 // Verify GBIC type (if any) and correct Tachyon Port State Machine
1820 // (GBIC) module definition is:
1821 // GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0. The input states appear
1822 // to be inverted -- i.e., a setting of 111 is read when there is NO
1823 // GBIC present. The Module Def (MD) spec says 000 is "no GBIC"
1824 // Hard code the bit states to detect Copper,
1825 // Long wave (single mode), Short wave (multi-mode), and absent GBIC
1826
1827 ULONG ulBuff;
1828
1829 sprintf( cErrorString, "\nGBIC detected: ");
1830
1831 ulBuff = fcChip->Registers.TYstatus.value & 0x13;
1832 switch( ulBuff )
1833 {
1834 case 0x13: // GPIO4, GPIO1, GPIO0 = 111; no GBIC!
1835 sprintf( &cErrorString[ strlen( cErrorString)],
1836 "NONE! ");
1837 return FALSE;
1838
1839
1840 case 0x11: // Copper GBIC detected
1841 sprintf( &cErrorString[ strlen( cErrorString)],
1842 "Copper. ");
1843 break;
1844
1845 case 0x10: // Long-wave (single mode) GBIC detected
1846 sprintf( &cErrorString[ strlen( cErrorString)],
1847 "Long-wave. ");
1848 break;
1849 case 0x1: // Short-wave (multi mode) GBIC detected
1850 sprintf( &cErrorString[ strlen( cErrorString)],
1851 "Short-wave. ");
1852 break;
1853 default: // unknown GBIC - presumably it will work (?)
1854 sprintf( &cErrorString[ strlen( cErrorString)],
1855 "Unknown. ");
1856
1857 break;
1858 } // end switch GBIC detection
1859
1860 return TRUE;
1861}
1862
1863
1864
1865
1866
1867
1868int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[])
1869{
1870 // Tachyon's Frame Manager LPSM in LinkDown state?
1871 // (For non-loop port, check PSM instead.)
1872 // return string with state and FALSE is Link Down
1873
1874 int LinkUp;
1875
1876 if( fcChip->Registers.FMstatus.value & 0x80 )
1877 LinkUp = FALSE;
1878 else
1879 LinkUp = TRUE;
1880
1881 sprintf( &cErrorString[ strlen( cErrorString)],
1882 " LPSM %Xh ",
1883 (fcChip->Registers.FMstatus.value >>4) & 0xf );
1884
1885
1886 switch( fcChip->Registers.FMstatus.value & 0xF0)
1887 {
1888 // bits set in LPSM
1889 case 0x10:
1890 sprintf( &cErrorString[ strlen( cErrorString)], "ARB");
1891 break;
1892 case 0x20:
1893 sprintf( &cErrorString[ strlen( cErrorString)], "ARBwon");
1894 break;
1895 case 0x30:
1896 sprintf( &cErrorString[ strlen( cErrorString)], "OPEN");
1897 break;
1898 case 0x40:
1899 sprintf( &cErrorString[ strlen( cErrorString)], "OPENed");
1900 break;
1901 case 0x50:
1902 sprintf( &cErrorString[ strlen( cErrorString)], "XmitCLS");
1903 break;
1904 case 0x60:
1905 sprintf( &cErrorString[ strlen( cErrorString)], "RxCLS");
1906 break;
1907 case 0x70:
1908 sprintf( &cErrorString[ strlen( cErrorString)], "Xfer");
1909 break;
1910 case 0x80:
1911 sprintf( &cErrorString[ strlen( cErrorString)], "Init");
1912 break;
1913 case 0x90:
1914 sprintf( &cErrorString[ strlen( cErrorString)], "O-IInitFin");
1915 break;
1916 case 0xa0:
1917 sprintf( &cErrorString[ strlen( cErrorString)], "O-IProtocol");
1918 break;
1919 case 0xb0:
1920 sprintf( &cErrorString[ strlen( cErrorString)], "O-ILipRcvd");
1921 break;
1922 case 0xc0:
1923 sprintf( &cErrorString[ strlen( cErrorString)], "HostControl");
1924 break;
1925 case 0xd0:
1926 sprintf( &cErrorString[ strlen( cErrorString)], "LoopFail");
1927 break;
1928 case 0xe0:
1929 sprintf( &cErrorString[ strlen( cErrorString)], "Offline");
1930 break;
1931 case 0xf0:
1932 sprintf( &cErrorString[ strlen( cErrorString)], "OldPort");
1933 break;
1934 case 0:
1935 default:
1936 sprintf( &cErrorString[ strlen( cErrorString)], "Monitor");
1937 break;
1938
1939 }
1940
1941 return LinkUp;
1942}
1943
1944
1945
1946
1947#include "linux/slab.h"
1948
1949// Dynamic memory allocation alignment routines
1950// HP's Tachyon Fibre Channel Controller chips require
1951// certain memory queues and register pointers to be aligned
1952// on various boundaries, usually the size of the Queue in question.
1953// Alignment might be on 2, 4, 8, ... or even 512 byte boundaries.
1954// Since most O/Ss don't allow this (usually only Cache aligned -
1955// 32-byte boundary), these routines provide generic alignment (after
1956// O/S allocation) at any boundary, and store the original allocated
1957// pointer for deletion (O/S free function). Typically, we expect
1958// these functions to only be called at HBA initialization and
1959// removal time (load and unload times)
1960// ALGORITHM notes:
1961// Memory allocation varies by compiler and platform. In the worst case,
1962// we are only assured BYTE alignment, but in the best case, we can
1963// request allocation on any desired boundary. Our strategy: pad the
1964// allocation request size (i.e. waste memory) so that we are assured
1965// of passing desired boundary near beginning of contiguous space, then
1966// mask out lower address bits.
1967// We define the following algorithm:
1968// allocBoundary - compiler/platform specific address alignment
1969// in number of bytes (default is single byte; i.e. 1)
1970// n_alloc - number of bytes application wants @ aligned address
1971// ab - alignment boundary, in bytes (e.g. 4, 32, ...)
1972// t_alloc - total allocation needed to ensure desired boundary
1973// mask - to clear least significant address bits for boundary
1974// Compute:
1975// t_alloc = n_alloc + (ab - allocBoundary)
1976// allocate t_alloc bytes @ alloc_address
1977// mask = NOT (ab - 1)
1978// (e.g. if ab=32 _0001 1111 -> _1110 0000
1979// aligned_address = alloc_address & mask
1980// set n_alloc bytes to 0
1981// return aligned_address (NULL if failed)
1982//
1983// If u32_AlignedAddress is non-zero, then search for BaseAddress (stored
1984// from previous allocation). If found, invoke call to FREE the memory.
1985// Return NULL if BaseAddress not found
1986
1987// we need about 8 allocations per HBA. Figuring at most 10 HBAs per server
1988// size the dynamic_mem array at 80.
1989
1990void* fcMemManager( struct pci_dev *pdev, ALIGNED_MEM *dynamic_mem,
1991 ULONG n_alloc, ULONG ab, ULONG u32_AlignedAddress,
1992 dma_addr_t *dma_handle)
1993{
1994 USHORT allocBoundary=1; // compiler specific - worst case 1
1995 // best case - replace malloc() call
1996 // with function that allocates exactly
1997 // at desired boundary
1998
1999 unsigned long ulAddress;
2000 ULONG t_alloc, i;
2001 void *alloc_address = 0; // def. error code / address not found
2002 LONG mask; // must be 32-bits wide!
2003
2004 ENTER("fcMemManager");
2005 if( u32_AlignedAddress ) // are we freeing existing memory?
2006 {
2007// printk(" freeing AlignedAddress %Xh\n", u32_AlignedAddress);
2008 for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for the base address
2009 {
2010// printk("dynamic_mem[%u].AlignedAddress %lX\n", i, dynamic_mem[i].AlignedAddress);
2011 if( dynamic_mem[i].AlignedAddress == u32_AlignedAddress )
2012 {
2013 alloc_address = dynamic_mem[i].BaseAllocated; // 'success' status
2014 pci_free_consistent(pdev,dynamic_mem[i].size,
2015 alloc_address,
2016 dynamic_mem[i].dma_handle);
2017 dynamic_mem[i].BaseAllocated = 0; // clear for next use
2018 dynamic_mem[i].AlignedAddress = 0;
2019 dynamic_mem[i].size = 0;
2020 break; // quit for loop; done
2021 }
2022 }
2023 }
2024 else if( n_alloc ) // want new memory?
2025 {
2026 dma_addr_t handle;
2027 t_alloc = n_alloc + (ab - allocBoundary); // pad bytes for alignment
2028// printk("pci_alloc_consistent() for Tach alignment: %ld bytes\n", t_alloc);
2029
2030// (would like to) allow thread block to free pages
2031 alloc_address = // total bytes (NumberOfBytes)
2032 pci_alloc_consistent(pdev, t_alloc, &handle);
2033
2034 // now mask off least sig. bits of address
2035 if( alloc_address ) // (only if non-NULL)
2036 {
2037 // find place to store ptr, so we
2038 // can free it later...
2039
2040 mask = (LONG)(ab - 1); // mask all low-order bits
2041 mask = ~mask; // invert bits
2042 for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for free slot
2043 {
2044 if( dynamic_mem[i].BaseAllocated == 0) // take 1st available
2045 {
2046 dynamic_mem[i].BaseAllocated = alloc_address;// address from O/S
2047 dynamic_mem[i].dma_handle = handle;
2048 if (dma_handle != NULL)
2049 {
2050// printk("handle = %p, ab=%d, boundary = %d, mask=0x%08x\n",
2051// handle, ab, allocBoundary, mask);
2052 *dma_handle = (dma_addr_t)
2053 ((((ULONG)handle) + (ab - allocBoundary)) & mask);
2054 }
2055 dynamic_mem[i].size = t_alloc;
2056 break;
2057 }
2058 }
2059 ulAddress = (unsigned long)alloc_address;
2060
2061 ulAddress += (ab - allocBoundary); // add the alignment bytes-
2062 // then truncate address...
2063 alloc_address = (void*)(ulAddress & mask);
2064
2065 dynamic_mem[i].AlignedAddress =
2066 (ULONG)(ulAddress & mask); // 32bit Tach address
2067 memset( alloc_address, 0, n_alloc ); // clear new memory
2068 }
2069 else // O/S dynamic mem alloc failed!
2070 alloc_address = 0; // (for debugging breakpt)
2071
2072 }
2073
2074 LEAVE("fcMemManager");
2075 return alloc_address; // good (or NULL) address
2076}
2077
2078
2079static Scsi_Host_Template driver_template = {
2080 .detect = cpqfcTS_detect,
2081 .release = cpqfcTS_release,
2082 .info = cpqfcTS_info,
2083 .proc_info = cpqfcTS_proc_info,
2084 .ioctl = cpqfcTS_ioctl,
2085 .queuecommand = cpqfcTS_queuecommand,
2086 .eh_device_reset_handler = cpqfcTS_eh_device_reset,
2087 .eh_abort_handler = cpqfcTS_eh_abort,
2088 .bios_param = cpqfcTS_biosparam,
2089 .can_queue = CPQFCTS_REQ_QUEUE_LEN,
2090 .this_id = -1,
2091 .sg_tablesize = SG_ALL,
2092 .cmd_per_lun = CPQFCTS_CMD_PER_LUN,
2093 .use_clustering = ENABLE_CLUSTERING,
2094};
2095#include "scsi_module.c"
2096
diff --git a/drivers/scsi/cpqfcTSioctl.h b/drivers/scsi/cpqfcTSioctl.h
deleted file mode 100644
index 825536969126..000000000000
--- a/drivers/scsi/cpqfcTSioctl.h
+++ /dev/null
@@ -1,94 +0,0 @@
1// for user apps, make sure data size types are defined
2// with
3
4
5#define CCPQFCTS_IOC_MAGIC 'Z'
6
7typedef struct
8{
9 __u8 bus;
10 __u8 dev_fn;
11 __u32 board_id;
12} cpqfc_pci_info_struct;
13
14typedef __u32 DriverVer_type;
15/*
16typedef union
17{
18 struct // Peripheral Unit Device
19 {
20 __u8 Bus:6;
21 __u8 Mode:2; // b00
22 __u8 Dev;
23 } PeripDev;
24 struct // Volume Set Address
25 {
26 __u8 DevMSB:6;
27 __u8 Mode:2; // b01
28 __u8 DevLSB;
29 } LogDev;
30 struct // Logical Unit Device (SCSI-3, SCC-2 defined)
31 {
32 __u8 Targ:6;
33 __u8 Mode:2; // b10
34 __u8 Dev:5;
35 __u8 Bus:3;
36
37 } LogUnit;
38} SCSI3Addr_struct;
39
40
41typedef struct
42{
43 SCSI3Addr_struct FCP_Nexus;
44 __u8 cdb[16];
45} PassThru_Command_struct;
46*/
47
48/* this is nearly duplicated in idashare.h */
49typedef struct {
50 int lc; /* Controller number */
51 int node; /* Node (box) number */
52 int ld; /* Logical Drive on this box, if required */
53 __u32 nexus; /* SCSI Nexus */
54 void *argp; /* Argument pointer */
55} VENDOR_IOCTL_REQ;
56
57
58typedef struct {
59 char cdb[16]; /* SCSI CDB for the pass-through */
60 ushort bus; /* Target bus on the box */
61 ushort pdrive; /* Physical drive on the box */
62 int len; /* Length of the data area of the CDB */
63 int sense_len; /* Length of the sense data */
64 char sense_data[40]; /* Sense data */
65 void *bufp; /* Data area for the CDB */
66 char rw_flag; /* Read CDB or Write CDB */
67} cpqfc_passthru_t;
68
69/*
70** Defines for the IOCTLS.
71*/
72
73#define VENDOR_READ_OPCODE 0x26
74#define VENDOR_WRITE_OPCODE 0x27
75
76#define CPQFCTS_GETPCIINFO _IOR( CCPQFCTS_IOC_MAGIC, 1, cpqfc_pci_info_struct)
77#define CPQFCTS_GETDRIVVER _IOR( CCPQFCTS_IOC_MAGIC, 9, DriverVer_type)
78
79#define CPQFCTS_SCSI_PASSTHRU _IOWR( CCPQFCTS_IOC_MAGIC,11, VENDOR_IOCTL_REQ)
80
81/* We would rather have equivalent generic, low-level driver agnostic
82ioctls that do what CPQFC_IOCTL_FC_TARGET_ADDRESS and
83CPQFC_IOCTL_FC_TDR 0x5388 do, but currently, we do not have them,
84consequently applications would have to know they are talking to cpqfc. */
85
86/* Used to get Fibre Channel WWN and port_id from device */
87// #define CPQFC_IOCTL_FC_TARGET_ADDRESS 0x5387
88#define CPQFC_IOCTL_FC_TARGET_ADDRESS \
89 _IOR( CCPQFCTS_IOC_MAGIC, 13, Scsi_FCTargAddress)
90
91/* Used to invoke Target Defice Reset for Fibre Channel */
92// #define CPQFC_IOCTL_FC_TDR 0x5388
93#define CPQFC_IOCTL_FC_TDR _IO( CCPQFCTS_IOC_MAGIC, 15)
94
diff --git a/drivers/scsi/cpqfcTSstructs.h b/drivers/scsi/cpqfcTSstructs.h
deleted file mode 100644
index 0bae3298c44b..000000000000
--- a/drivers/scsi/cpqfcTSstructs.h
+++ /dev/null
@@ -1,1530 +0,0 @@
1/* Copyright(c) 2000, Compaq Computer Corporation
2 * Fibre Channel Host Bus Adapter 64-bit, 66MHz PCI
3 * Originally developed and tested on:
4 * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ...
5 * SP# P225CXCBFIEL6T, Rev XC
6 * SP# 161290-001, Rev XD
7 * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2, or (at your option) any
12 * later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 * Written by Don Zimmerman
19*/
20#ifndef CPQFCTSSTRUCTS_H
21#define CPQFCTSSTRUCTS_H
22
23#include <linux/timer.h> // timer declaration in our host data
24#include <linux/interrupt.h>
25#include <asm/atomic.h>
26#include "cpqfcTSioctl.h"
27
28#define DbgDelay(secs) { int wait_time; printk( " DbgDelay %ds ", secs); \
29 for( wait_time=jiffies + (secs*HZ); \
30 time_before(jiffies, wait_time) ;) ; }
31
32#define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
33// don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c
34#define VER_MAJOR 2
35#define VER_MINOR 5
36#define VER_SUBMINOR 4
37
38// Macros for kernel (esp. SMP) tracing using a PCI analyzer
39// (e.g. x86).
40//#define PCI_KERNEL_TRACE
41#ifdef PCI_KERNEL_TRACE
42#define PCI_TRACE(x) inl( fcChip->Registers.IOBaseL +x);
43#define PCI_TRACEO(x,y) outl( x, (fcChip->Registers.IOBaseL +y));
44#else
45
46#define PCI_TRACE(x)
47#define PCI_TRACEO(x,y)
48#endif
49
50
51//#define DEBUG_CMND 1 // debug output for Linux Scsi CDBs
52//#define DUMMYCMND_DBG 1
53
54//#define DEBUG_CPQFCTS 1
55//#undef DEBUG_CPQFCTS
56#ifdef DEBUG_CPQFCTS
57#define ENTER(x) printk("cpqfcts : entering %s()\n", x);
58#define LEAVE(x) printk("cpqfcts : leaving %s()\n", x);
59#define DEBUG(x) x
60#else
61#define ENTER(x)
62#define LEAVE(x)
63#define DEBUG(x)
64#endif /* DEBUG_CPQFCTS */
65
66//#define DEBUG_CPQFCTS_PCI 1
67//#undef DEBUG_CPQFCTS_PCI
68#if DEBUG_CPQFCTS_PCI
69#define DEBUG_PCI(x) x
70#else
71#define DEBUG_PCI(x)
72#endif /* DEBUG_CPQFCTS_PCI */
73
74#define STACHLITE66_TS12 "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.2"
75#define STACHLITE66_TS13 "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.3"
76#define STACHLITE_UNKNOWN "Compaq FibreChannel HBA Tachyon Chip/Board Ver??"
77#define SAGILENT_XL2_21 "Agilent FC HBA, Tachyon XL2 HPFC-5200B/2.1"
78
79// PDA is Peripheral Device Address, VSA is Volume Set Addressing
80// Linux SCSI parameters
81#define CPQFCTS_MAX_TARGET_ID 64
82
83// Note, changing CPQFCTS_MAX_LUN to less than 32 (e.g, 8) will result in
84// strange behavior if a box with more than, e.g. 8, is on the loop.
85#define CPQFCTS_MAX_LUN 32 // The RA-4x00 supports 32 (Linux SCSI supports 8)
86#define CPQFCTS_MAX_CHANNEL 0 // One FC port on cpqfcTS HBA
87
88#define CPQFCTS_CMD_PER_LUN 15 // power of 2 -1, must be >0
89#define CPQFCTS_REQ_QUEUE_LEN (TACH_SEST_LEN/2) // must be < TACH_SEST_LEN
90
91#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
92#ifndef DECLARE_MUTEX_LOCKED
93#define DECLARE_MUTEX_LOCKED(sem) struct semaphore sem = MUTEX_LOCKED
94#endif
95
96#define DEV_NAME "cpqfcTS"
97
98struct SupportedPCIcards
99{
100 __u16 vendor_id;
101 __u16 device_id;
102};
103
104// nn:nn denotes bit field
105 // TachyonHeader struct def.
106 // the fields shared with ODB
107 // need to have same value
108
109
110
111
112#ifndef BYTE
113//typedef UCHAR BYTE;
114typedef __u8 BYTE;
115#endif
116#ifndef UCHAR
117typedef __u8 UCHAR;
118#endif
119#ifndef LONG
120typedef __s32 LONG;
121#endif
122#ifndef ULONG
123typedef __u32 ULONG;
124#endif
125#ifndef PVOID
126typedef void * PVOID;
127#endif
128#ifndef USHORT
129typedef __u16 USHORT;
130#endif
131#ifndef BOOLEAN
132typedef __u8 BOOLEAN;
133#endif
134
135
136// macro for FC-PH reject codes
137// payload format for LS_RJT (FC payloads are big endian):
138// byte 0 1 2 3 (MSB)
139// DWORD 0 01 00 00 00
140// DWORD 1 resvd code expl. vendor
141
142#define LS_RJT_REASON( code, expl) (( code<<8) | (expl <<16))
143
144
145#define TachLiteSTATUS 0x12
146
147// Fibre Channel EXCHANGE status codes for Tachyon chips/ driver software
148// 32-bit ERROR word defines
149#define INVALID_ARGS 0x1
150#define LNKDWN_OSLS 0x2
151#define LNKDWN_LASER 0x4
152#define OUTQUE_FULL 0x8
153#define DRIVERQ_FULL 0x10
154#define SEST_FULL 0x20
155#define BAD_ALPA 0x40
156#define OVERFLOW 0x80 // inbound CM
157#define COUNT_ERROR 0x100 // inbound CM
158#define LINKFAIL_RX 0x200 // inbound CM
159#define ABORTSEQ_NOTIFY 0x400 // outbound CM
160#define LINKFAIL_TX 0x800 // outbound CM
161#define HOSTPROG_ERR 0x1000 // outbound CM
162#define FRAME_TO 0x2000 // outbound CM
163#define INV_ENTRY 0x4000 // outbound CM
164#define SESTPROG_ERR 0x8000 // outbound CM
165#define OUTBOUND_TIMEOUT 0x10000L // timeout waiting for Tachyon outbound CM
166#define INITIATOR_ABORT 0x20000L // initiator exchange timeout or O/S ABORT
167#define MEMPOOL_FAIL 0x40000L // O/S memory pool allocation failed
168#define FC2_TIMEOUT 0x80000L // driver timeout for lost frames
169#define TARGET_ABORT 0x100000L // ABTS received from FC port
170#define EXCHANGE_QUEUED 0x200000L // e.g. Link State was LDn on fcStart
171#define PORTID_CHANGED 0x400000L // fc Port address changed
172#define DEVICE_REMOVED 0x800000L // fc Port address changed
173// Several error scenarios result in SEST Exchange frames
174// unexpectedly arriving in the SFQ
175#define SFQ_FRAME 0x1000000L // SFQ frames from open Exchange
176
177// Maximum number of Host Bus Adapters (HBA) / controllers supported
178// only important for mem allocation dimensions - increase as necessary
179
180#define MAX_ADAPTERS 8
181#define MAX_RX_PAYLOAD 1024 // hardware dependent max frame payload
182// Tach header struc defines
183#define SOFi3 0x7
184#define SOFf 0x8
185#define SOFn3 0xB
186#define EOFn 0x5
187#define EOFt 0x6
188
189// FCP R_CTL defines
190#define FCP_CMND 0x6
191#define FCP_XFER_RDY 0x5
192#define FCP_RSP 0x7
193#define FCP_RESPONSE 0x777 // (arbitrary #)
194#define NEED_FCP_RSP 0x77 // (arbitrary #)
195#define FCP_DATA 0x1
196
197#define RESET_TACH 0x100 // Reset Tachyon/TachLite
198#define SCSI_IWE 0x2000 // initiator write entry (for SEST)
199#define SCSI_IRE 0x3000 // initiator read entry (for SEST)
200#define SCSI_TRE 0x400 // target read entry (for SEST)
201#define SCSI_TWE 0x500 // target write entry (for SEST)
202#define TOGGLE_LASER 0x800
203#define LIP 0x900
204#define CLEAR_FCPORTS 99 // (arbitrary #) free mem for Logged in ports
205#define FMINIT 0x707 // (arbitrary) for Frame Manager Init command
206
207// BLS == Basic Link Service
208// ELS == Extended Link Service
209#define BLS_NOP 4
210#define BLS_ABTS 0x10 // FC-PH Basic Link Service Abort Sequence
211#define BLS_ABTS_ACC 0x100 // FC-PH Basic Link Service Abort Sequence Accept
212#define BLS_ABTS_RJT 0x101 // FC-PH Basic Link Service Abort Sequence Reject
213#define ELS_PLOGI 0x03 // FC-PH Port Login (arbitrary assign)
214#define ELS_SCR 0x70 // (arb assign) State Change Registration (Fabric)
215#define FCS_NSR 0x72 // (arb assign) Name Service Request (Fabric)
216#define ELS_FLOGI 0x44 // (arb assign) Fabric Login
217#define ELS_FDISC 0x41 // (arb assign) Fabric Discovery (Login)
218#define ELS_PDISC 0x50 // FC-PH2 Port Discovery
219#define ELS_ABTX 0x06 // FC-PH Abort Exchange
220#define ELS_LOGO 0x05 // FC-PH Port Logout
221#define ELS_PRLI 0x20 // FCP-SCSI Process Login
222#define ELS_PRLO 0x21 // FCP-SCSI Process Logout
223#define ELS_LOGO_ACC 0x07 // {FC-PH} Port Logout Accept
224#define ELS_PLOGI_ACC 0x08 // {FC-PH} Port Login Accept
225#define ELS_ACC 0x18 // {FC-PH} (generic) ACCept
226#define ELS_PRLI_ACC 0x22 // {FCP-SCSI} Process Login Accept
227#define ELS_RJT 0x1000000
228#define SCSI_REPORT_LUNS 0x0A0
229#define FCP_TARGET_RESET 0x200
230
231#define ELS_LILP_FRAME 0x00000711 // 1st payload word of LILP frame
232
233#define SFQ_UNASSISTED_FCP 1 // ICM, DWord3, "Type" unassisted FCP
234#define SFQ_UNKNOWN 0x31 // (arbitrary) ICM, DWord3, "Type" unknown
235
236// these "LINK" bits refer to loop or non-loop
237#define LINKACTIVE 0x2 // fcLinkQ type - LINK UP Tachyon FM 'Lup' bit set
238#define LINKDOWN 0xf2 // fcLinkQ type - LINK DOWN Tachyon FM 'Ldn' bit set
239
240//#define VOLUME_SET_ADDRESSING 1 // "channel" or "bus" 1
241
242typedef struct // 32 bytes hdr ONLY (e.g. FCP_DATA buffer for SEST)
243{
244 ULONG reserved; // dword 0 (don't use)
245 ULONG sof_eof;
246 ULONG d_id; // dword 2 - 31:24 R_CTL, 23:0 D_ID
247 ULONG s_id; // dword 3 - 31:24 CS_CTL, 23:0 S_ID
248 ULONG f_ctl; // dword 4 - 31:24 Type, 23:0 F_CTL
249 ULONG seq_cnt; // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
250 ULONG ox_rx_id; // dword 6 - 31:16 OX_ID, 15:0 RX_ID
251 ULONG ro; // dword 7 - relative offset
252} TachFCHDR;
253
254 // NOTE!! the following struct MUST be 64 bytes.
255typedef struct // 32 bytes hdr + 32 bytes payload
256{
257 ULONG reserved; // dword 0 (don't use - must clear to 0)
258 ULONG sof_eof; // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
259 ULONG d_id; // dword 2 - 31:24 R_CTL, 23:0 D_ID
260 ULONG s_id; // dword 3 - 31:24 CS_CTL, 23:0 S_ID
261 ULONG f_ctl; // dword 4 - 31:24 Type, 23:0 F_CTL
262 ULONG seq_cnt; // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
263 ULONG ox_rx_id; // dword 6 - 31:16 OX_ID, 15:0 RX_ID
264 ULONG ro; // dword 7 - relative offset
265//---------
266 __u32 pl[8]; // dwords 8-15 frame data payload
267} TachFCHDR_CMND;
268
269
270typedef struct // 32 bytes hdr + 120 bytes payload
271{
272 ULONG reserved; // dword 0 (don't use - must clear to 0)
273 ULONG sof_eof; // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
274 ULONG d_id; // dword 2 - 31:24 R_CTL, 23:0 D_ID
275 ULONG s_id; // dword 3 - 31:24 CS_CTL, 23:0 S_ID
276 ULONG f_ctl; // dword 4 - 31:24 Type, 23:0 F_CTL
277 ULONG seq_cnt; // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
278 ULONG ox_rx_id; // dword 6 - 31:16 OX_ID, 15:0 RX_ID
279 ULONG ro; // dword 7 - relative offset
280//---------
281 __u32 pl[30]; // largest necessary payload (for LOGIN cmnds)
282} TachFCHDR_GCMND;
283
284typedef struct // 32 bytes hdr + 64 bytes payload
285{
286 ULONG reserved; // dword 0 (don't use)
287 ULONG sof_eof;
288 ULONG d_id; // dword 2 - 31:24 R_CTL, 23:0 D_ID
289 ULONG s_id; // dword 3 - 31:24 CS_CTL, 23:0 S_ID
290 ULONG f_ctl; // dword 4 - 31:24 Type, 23:0 F_CTL
291 ULONG seq_cnt; // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
292 ULONG ox_rx_id; // dword 6 - 31:16 OX_ID, 15:0 RX_ID
293 ULONG ro; // dword 7 - relative offset
294//---------
295 __u32 pl[18]; // payload for FCP-RSP (response buffer) RA-4x00 is 72bytes
296} TachFCHDR_RSP;
297
298
299
300
301
302
303// Inbound Message Queue structures...
304typedef struct // each entry 8 words (32 bytes)
305{
306 ULONG type; // IMQ completion message types
307 ULONG word[7]; // remainder of structure
308 // interpreted by IMQ type
309} TachyonIMQE;
310
311
312// Queues for TachLite not in original Tachyon
313// ERQ - Exchange Request Queue (for outbound commands)
314// SFQ - Single Frame Queue (for incoming frames)
315
316 // Define Tachyon Outbound Command Que
317 // (Since many Tachyon registers are Read
318 // only, maintain copies for debugging)
319 // most Tach ques need power-of-2 sizes,
320 // where registers are loaded with po2 -1
321#define TACH_SEST_LEN 512 // TachLite SEST
322
323#define ELS_EXCHANGES 64 // e.g. PLOGI, RSCN, ...
324// define the total number of outstanding (simultaneous) exchanges
325#define TACH_MAX_XID (TACH_SEST_LEN + ELS_EXCHANGES) // ELS exchanges
326
327#define ERQ_LEN 128 // power of 2, max 4096
328
329// Inbound Message Queue structures...
330#define IMQ_LEN 512 // minimum 4 entries [(power of 2) - 1]
331typedef struct // 8 words - 32 bytes
332{
333 TachyonIMQE QEntry[IMQ_LEN];
334 ULONG producerIndex; // IMQ Producer Index register
335 // @32 byte align
336 ULONG consumerIndex; // Consumer Index register (in Tachyon)
337 ULONG length; // Length register
338 ULONG base;
339} TachyonIMQ; // @ 32 * IMQ_LEN align
340
341
342
343typedef struct // inbound completion message
344{
345 ULONG Type;
346 ULONG Index;
347 ULONG TransferLength;
348} TachyonInbCM;
349
350
351
352// arbitrary numeric tags for TL structures
353#define TL_FCHS 1 // TachLite Fibre Channel Header Structure
354#define TL_IWE 2 // initiator write entry (for SEST)
355#define TL_TWE 3 // target write entry (for SEST)
356#define TL_IRE 4 // initiator read entry (for SEST)
357#define TL_TRE 5 // target read entry (for SEST)
358#define TL_IRB 6 // I/O request block
359
360 // for INCOMING frames
361#define SFQ_LEN 32 // minimum 32 entries, max 4096
362
363typedef struct // Single Frame Que
364{
365 TachFCHDR_CMND QEntry[SFQ_LEN]; // must be 64 bytes!!
366 ULONG producerIndex; // IMQ Producer Index register
367 // @32 byte align
368 ULONG consumerIndex; // Consumer Index register (in Tachyon)
369 ULONG length; // Length register
370 ULONG base;
371} TachLiteSFQ;
372
373
374typedef struct // I/O Request Block flags
375{
376 UCHAR BRD : 1;
377 UCHAR : 1; // reserved
378 UCHAR SFA : 1;
379 UCHAR DNC : 1;
380 UCHAR DIN : 1;
381 UCHAR DCM : 1;
382 UCHAR CTS : 1;
383 UCHAR SBV : 1; // IRB entry valid - IRB'B' only
384} IRBflags;
385
386typedef struct // I/O Request Block
387{ // Request 'A'
388 ULONG Req_A_SFS_Len; // total frame len (hdr + payload), min 32
389 ULONG Req_A_SFS_Addr; // 32-bit pointer to FCHS struct (to be sent)
390 ULONG Req_A_SFS_D_ID; // 24-bit FC destination (i.e. 8 bit al_pa)
391 ULONG Req_A_Trans_ID; // X_ID (OX_ID or RX_ID) and/or Index in SEST
392 // Request 'B'
393 ULONG Req_B_SFS_Len; // total frame len (hdr + payload), min 32
394 ULONG Req_B_SFS_Addr; // 32-bit pointer to FCHS struct (to be sent)
395 ULONG Req_B_SFS_D_ID; // 24-bit FC destination (i.e. 8 bit al_pa)
396 ULONG Req_B_Trans_ID; // X_ID (OX_ID or RX_ID) and/or Index in SEST
397} TachLiteIRB;
398
399
400typedef struct // TachLite placeholder for IRBs
401{ // aligned @sizeof(ERQ) for TachLite
402 // MAX commands is sum of SEST len and ERQ
403 // we know that each SEST entry requires an
404 // IRB (ERQ) entry; in addition, we provide
405 // ERQ_LEN
406 TachLiteIRB QEntry[ERQ_LEN]; // Base register; entries 32 bytes ea.
407 ULONG consumerIndex; // Consumer Index register
408 ULONG producerIndex; // ERQ Producer Index register
409 ULONG length; // Length register
410 ULONG base; // copy of base ptr for debug
411 // struct is sized for largest expected cmnd (LOGIN)
412} TachLiteERQ;
413
414// for now, just 32 bit DMA, eventually 40something, with code changes
415#define CPQFCTS_DMA_MASK ((unsigned long) (0x00000000FFFFFFFF))
416
417#define TL_MAX_SG_ELEM_LEN 0x7ffff // Max buffer length a single S/G entry
418 // may represent (a hardware limitation). The
419 // only reason to ever change this is if you
420 // want to exercise very-hard-to-reach code in
421 // cpqfcTSworker.c:build_SEST_sglist().
422
423#define TL_DANGER_SGPAGES 7 // arbitrary high water mark for # of S/G pages
424 // we must exceed to elicit a warning indicative
425 // of EXTREMELY large data transfers or
426 // EXTREME memory fragmentation.
427 // (means we just used up 2048 S/G elements,
428 // Never seen this is real life, only in
429 // testing with tricked up driver.)
430
431#define TL_EXT_SG_PAGE_COUNT 256 // Number of Extended Scatter/Gather a/l PAIRS
432 // Tachyon register (IOBaseU 0x68)
433 // power-of-2 value ONLY! 4 min, 256 max
434
435 // byte len is #Pairs * 2 ULONG/Pair * 4 bytes/ULONG
436#define TL_EXT_SG_PAGE_BYTELEN (TL_EXT_SG_PAGE_COUNT *2 *4)
437
438
439
440// SEST entry types: IWE, IRE, TWE, TRE
441typedef struct
442{
443 ULONG Hdr_Len;
444 ULONG Hdr_Addr;
445 ULONG RSP_Len;
446 ULONG RSP_Addr;
447 ULONG Buff_Off;
448#define USES_EXTENDED_SGLIST(this_sest, x_ID) \
449 (!((this_sest)->u[ x_ID ].IWE.Buff_Off & 0x80000000))
450 ULONG Link;
451 ULONG RX_ID;
452 ULONG Data_Len;
453 ULONG Exp_RO;
454 ULONG Exp_Byte_Cnt;
455 // --- extended/local Gather Len/Address pairs
456 ULONG GLen1;
457 ULONG GAddr1;
458 ULONG GLen2;
459 ULONG GAddr2;
460 ULONG GLen3;
461 ULONG GAddr3;
462} TachLiteIWE;
463
464
465typedef struct
466{
467 ULONG Seq_Accum;
468 ULONG reserved; // must clear to 0
469 ULONG RSP_Len;
470 ULONG RSP_Addr;
471 ULONG Buff_Off;
472 ULONG Buff_Index; // ULONG 5
473 ULONG Exp_RO;
474 ULONG Byte_Count;
475 ULONG reserved_; // ULONG 8
476 ULONG Exp_Byte_Cnt;
477 // --- extended/local Scatter Len/Address pairs
478 ULONG SLen1;
479 ULONG SAddr1;
480 ULONG SLen2;
481 ULONG SAddr2;
482 ULONG SLen3;
483 ULONG SAddr3;
484} TachLiteIRE;
485
486
487typedef struct // Target Write Entry
488{
489 ULONG Seq_Accum; // dword 0
490 ULONG reserved; // dword 1 must clear to 0
491 ULONG Remote_Node_ID;
492 ULONG reserved1; // dword 3 must clear to 0
493 ULONG Buff_Off;
494 ULONG Buff_Index; // ULONG 5
495 ULONG Exp_RO;
496 ULONG Byte_Count;
497 ULONG reserved_; // ULONG 8
498 ULONG Exp_Byte_Cnt;
499 // --- extended/local Scatter Len/Address pairs
500 ULONG SLen1;
501 ULONG SAddr1;
502 ULONG SLen2;
503 ULONG SAddr2;
504 ULONG SLen3;
505 ULONG SAddr3;
506} TachLiteTWE;
507
508typedef struct
509{
510 ULONG Hdr_Len;
511 ULONG Hdr_Addr;
512 ULONG RSP_Len; // DWord 2
513 ULONG RSP_Addr;
514 ULONG Buff_Off;
515 ULONG Buff_Index; // DWord 5
516 ULONG reserved;
517 ULONG Data_Len;
518 ULONG reserved_;
519 ULONG reserved__;
520 // --- extended/local Gather Len/Address pairs
521 ULONG GLen1; // DWord A
522 ULONG GAddr1;
523 ULONG GLen2;
524 ULONG GAddr2;
525 ULONG GLen3;
526 ULONG GAddr3;
527} TachLiteTRE;
528
529typedef struct ext_sg_page_ptr_t *PSGPAGES;
530typedef struct ext_sg_page_ptr_t
531{
532 unsigned char page[TL_EXT_SG_PAGE_BYTELEN * 2]; // 2x for alignment
533 dma_addr_t busaddr; // need the bus addresses and
534 unsigned int maplen; // lengths for later pci unmapping.
535 PSGPAGES next;
536} SGPAGES; // linked list of S/G pairs, by Exchange
537
538typedef struct // SCSI Exchange State Table
539{
540 union // Entry can be IWE, IRE, TWE, TRE
541 { // 64 bytes per entry
542 TachLiteIWE IWE;
543 TachLiteIRE IRE;
544 TachLiteTWE TWE;
545 TachLiteTRE TRE;
546 } u[TACH_SEST_LEN];
547
548 TachFCHDR DataHDR[TACH_SEST_LEN]; // for SEST FCP_DATA frame hdr (no pl)
549 TachFCHDR_RSP RspHDR[TACH_SEST_LEN]; // space for SEST FCP_RSP frame
550 PSGPAGES sgPages[TACH_SEST_LEN]; // head of linked list of Pool-allocations
551 ULONG length; // Length register
552 ULONG base; // copy of base ptr for debug
553} TachSEST;
554
555
556
557typedef struct // each register has it's own address
558 // and value (used for write-only regs)
559{
560 void* address;
561 volatile ULONG value;
562} FCREGISTER;
563
564typedef struct // Host copy - TachLite Registers
565{
566 ULONG IOBaseL, IOBaseU; // I/O port lower and upper TL register addresses
567 ULONG MemBase; // memory mapped register addresses
568 void* ReMapMemBase; // O/S VM reference for MemBase
569 ULONG wwn_hi; // WWN is set once at startup
570 ULONG wwn_lo;
571 ULONG my_al_pa; // al_pa received after LIP()
572 ULONG ROMCTR; // flags for on-board RAM/ROM
573 ULONG RAMBase; // on-board RAM (i.e. some Tachlites)
574 ULONG SROMBase; // on-board EEPROM (some Tachlites)
575 ULONG PCIMCTR; // PCI Master Control Reg (has bus width)
576
577 FCREGISTER INTEN; // copy of interrupt enable mask
578 FCREGISTER INTPEND; // interrupt pending
579 FCREGISTER INTSTAT; // interrupt status
580 FCREGISTER SFQconsumerIndex;
581 FCREGISTER ERQproducerIndex;
582 FCREGISTER TYconfig; // TachYon (chip level)
583 FCREGISTER TYcontrol;
584 FCREGISTER TYstatus;
585 FCREGISTER FMconfig; // Frame Manager (FC loop level)
586 FCREGISTER FMcontrol;
587 FCREGISTER FMstatus;
588 FCREGISTER FMLinkStatus1;
589 FCREGISTER FMLinkStatus2;
590 FCREGISTER FMBB_CreditZero;
591 FCREGISTER status;
592 FCREGISTER ed_tov; // error detect time-out value
593 FCREGISTER rcv_al_pa; // received arb. loop physical address
594 FCREGISTER primitive; // e.g. LIP(), OPN(), ...
595} TL_REGISTERS;
596
597
598
599typedef struct
600{
601 ULONG ok;
602 ULONG invalidArgs;
603 ULONG linkDown;
604 ULONG linkUp;
605 ULONG outQueFull;
606 ULONG SESTFull;
607 ULONG hpe; // host programming err (from Tach)
608 ULONG FC4aborted; // aborts from Application or upper driver layer
609 ULONG FC2aborted; // aborts from our driver's timeouts
610 ULONG timeouts; // our driver timeout (on individual exchanges)
611 ULONG logouts; // explicit - sent LOGO; implicit - device removed
612 ULONG retries;
613 ULONG linkFailTX;
614 ULONG linkFailRX;
615 ULONG CntErrors; // byte count expected != count received (typ. SEST)
616 ULONG e_stores; // elastic store errs
617 ULONG resets; // hard or soft controller resets
618 ULONG FMinits; // TACH Frame Manager Init (e.g. LIPs)
619 ULONG lnkQueFull; // too many LOGIN, loop commands
620 ULONG ScsiQueFull; // too many FCP-SCSI inbound frames
621 ULONG LossofSignal; // FM link status 1 regs
622 ULONG BadRXChar; // FM link status 1 regs
623 ULONG LossofSync; // FM link status 1 regs
624 ULONG Rx_EOFa; // FM link status 2 regs (received EOFa)
625 ULONG Dis_Frm; // FM link status 2 regs (discarded frames)
626 ULONG Bad_CRC; // FM link status 2 regs
627 ULONG BB0_Timer; // FM BB_Credit Zero Timer Reg
628 ULONG loopBreaks; // infinite loop exits
629 ULONG lastBB0timer; // static accum. buffer needed by Tachlite
630} FCSTATS;
631
632
633typedef struct // Config Options
634{ // LS Bit first
635 USHORT : 1; // bit0:
636 USHORT flogi : 1; // bit1: We sent FLOGI - wait for Fabric logins
637 USHORT fabric: 1; // bit2: Tachyon detected Fabric (FM stat LG)
638 USHORT LILPin: 1; // bit3: We can use an FC-AL LILP frame
639 USHORT target: 1; // bit4: this Port has SCSI target capability
640 USHORT initiator: 1; // bit5: this Port has SCSI initiator capability
641 USHORT extLoopback: 1; // bit6: loopback at GBIC
642 USHORT intLoopback: 1; // bit7: loopback in HP silicon
643 USHORT : 1; // bit8:
644 USHORT : 1; // bit9:
645 USHORT : 1; // bit10:
646 USHORT : 1; // bit11:
647 USHORT : 1; // bit12:
648 USHORT : 1; // bit13:
649 USHORT : 1; // bit14:
650 USHORT : 1; // bit15:
651} FC_OPTIONS;
652
653
654
655typedef struct dyn_mem_pair
656{
657 void *BaseAllocated; // address as allocated from O/S;
658 unsigned long AlignedAddress; // aligned address (used by Tachyon DMA)
659 dma_addr_t dma_handle;
660 size_t size;
661} ALIGNED_MEM;
662
663
664
665
666// these structs contain only CRUCIAL (stuff we actually use) parameters
667// from FC-PH(n) logins. (Don't save entire LOGIN payload to save mem.)
668
669// Implicit logout happens when the loop goes down - we require PDISC
670// to restore. Explicit logout is when WE decide never to talk to someone,
671// or when a target refuses to talk to us, i.e. sends us a LOGO frame or
672// LS_RJT reject in response to our PLOGI request.
673
674#define IMPLICIT_LOGOUT 1
675#define EXPLICIT_LOGOUT 2
676
677typedef struct
678{
679 UCHAR channel; // SCSI "bus"
680 UCHAR target;
681 UCHAR InqDeviceType; // byte 0 from SCSI Inquiry response
682 UCHAR VolumeSetAddressing; // FCP-SCSI LUN coding (40h for VSA)
683 UCHAR LunMasking; // True if selective presentation supported
684 UCHAR lun[CPQFCTS_MAX_LUN];
685} SCSI_NEXUS;
686
687
688typedef struct
689{
690 union
691 {
692 UCHAR ucWWN[8]; // a FC 64-bit World Wide Name/ PortID of target
693 // addressing of single target on single loop...
694 u64 liWWN;
695 } u;
696
697 ULONG port_id; // a FC 24-bit address of port (lower 8 bits = al_pa)
698
699#define REPORT_LUNS_PL 256
700 UCHAR ReportLunsPayload[REPORT_LUNS_PL];
701
702 SCSI_NEXUS ScsiNexus; // LUNs per FC device
703
704 ULONG LOGO_counter; // might try several times before logging out for good
705 ULONG LOGO_timer; // after LIP, ports expecting PDISC must time-out and
706 // LOGOut if successful PDISC not completed in 2 secs
707
708 ULONG concurrent_seq; // must be 1 or greater
709 ULONG rx_data_size; // e.g. 128, 256, 1024, 2048 per FC-PH spec
710 ULONG BB_credit;
711 ULONG EE_credit;
712
713 ULONG fcp_info; // from PRLI (i.e. INITIATOR/ TARGET flags)
714 // flags for login process
715 BOOLEAN Originator; // Login sequence Originated (if false, we
716 // responded to another port's login sequence)
717 BOOLEAN plogi; // PLOGI frame ACCepted (originated or responded)
718 BOOLEAN pdisc; // PDISC frame was ORIGINATED (self-login logic)
719 BOOLEAN prli; // PRLI frame ACCepted (originated or responded)
720 BOOLEAN flogi; // FLOGI frame ACCepted (originated or responded)
721 BOOLEAN logo; // port permanently logged out (invalid login param)
722 BOOLEAN flogiReq; // Fabric login required (set in LIP process)
723 UCHAR highest_ver;
724 UCHAR lowest_ver;
725
726
727 // when the "target" (actually FC Port) is waiting for login
728 // (e.g. after Link reset), set the device_blocked bit;
729 // after Port completes login, un-block target.
730 UCHAR device_blocked; // see Scsi_Device struct
731
732 // define singly-linked list of logged-in ports
733 // once a port_id is identified, it is remembered,
734 // even if the port is removed indefinitely
735 PVOID pNextPort; // actually, type PFC_LOGGEDIN_PORT; void for Compiler
736
737} FC_LOGGEDIN_PORT, *PFC_LOGGEDIN_PORT;
738
739
740
741// This serves as the ESB (Exchange Status Block),
742// and has timeout counter; used for ABORTs
743typedef struct
744{ // FC-1 X_IDs
745 ULONG type; // ELS_PLOGI, SCSI_IWE, ... (0 if free)
746 PFC_LOGGEDIN_PORT pLoggedInPort; // FC device on other end of Exchange
747 Scsi_Cmnd *Cmnd; // Linux SCSI command packet includes S/G list
748 ULONG timeOut; // units of ??, DEC by driver, Abort when 0
749 ULONG reTries; // need one or more retries?
750 ULONG status; // flags indicating errors (0 if none)
751 TachLiteIRB IRB; // I/O Request Block, gets copied to ERQ
752 TachFCHDR_GCMND fchs; // location of IRB's Req_A_SFS_Addr
753} FC_EXCHANGE, *PFC_EXCHANGE;
754
755// Unfortunately, Linux limits our kmalloc() allocations to 128k.
756// Because of this and the fact that our ScsiRegister allocation
757// is also constrained, we move this large structure out for
758// allocation after Scsi Register.
759// (In other words, this cumbersome indirection is necessary
760// because of kernel memory allocation constraints!)
761
762typedef struct // we will allocate this dynamically
763{
764 FC_EXCHANGE fcExchange[ TACH_MAX_XID ];
765} FC_EXCHANGES;
766
767
768
769
770
771
772
773
774
775
776
777typedef struct
778{
779 char Name[64]; // name of controller ("HP Tachlite TL Rev2.0, 33MHz, 64bit bus")
780 //PVOID pAdapterDevExt; // back pointer to device object/extension
781 ULONG ChipType; // local numeric key for Tachyon Type / Rev.
782 ULONG status; // our Driver - logical status
783
784 TL_REGISTERS Registers; // reg addresses & host memory copies
785 // FC-4 mapping of 'transaction' to X_IDs
786 UCHAR LILPmap[32*4]; // Loop Position Map of ALPAs (late FC-AL only)
787 FC_OPTIONS Options; // e.g. Target, Initiator, loopback...
788 UCHAR highest_FCPH_ver; // FC-PH version limits
789 UCHAR lowest_FCPH_ver; // FC-PH version limits
790
791 FC_EXCHANGES *Exchanges;
792 ULONG fcLsExchangeLRU; // Least Recently Used counter (Link Service)
793 ULONG fcSestExchangeLRU; // Least Recently Used counter (FCP-SCSI)
794 FC_LOGGEDIN_PORT fcPorts; // linked list of every FC port ever seen
795 FCSTATS fcStats; // FC comm err counters
796
797 // Host memory QUEUE pointers
798 TachLiteERQ *ERQ; // Exchange Request Que
799 TachyonIMQ *IMQ; // Inbound Message Que
800 TachLiteSFQ *SFQ; // Single Frame Queue
801 TachSEST *SEST; // SCSI Exchange State Table
802
803 dma_addr_t exch_dma_handle;
804
805 // these function pointers are for "generic" functions, which are
806 // replaced with Host Bus Adapter types at
807 // runtime.
808 int (*CreateTachyonQues)( void* , int);
809 int (*DestroyTachyonQues)( void* , int);
810 int (*LaserControl)(void*, int ); // e.g. On/Off
811 int (*ResetTachyon)(void*, int );
812 void (*FreezeTachyon)(void*, int );
813 void (*UnFreezeTachyon)(void*, int );
814 int (*InitializeTachyon)(void*, int, int );
815 int (*InitializeFrameManager)(void*, int );
816 int (*ProcessIMQEntry)(void*);
817 int (*ReadWriteWWN)(void*, int ReadWrite);
818 int (*ReadWriteNVRAM)(void*, void*, int ReadWrite);
819
820} TACHYON, *PTACHYON;
821
822
823void cpqfcTSClearLinkStatusCounters(TACHYON * fcChip);
824
825int CpqTsCreateTachLiteQues( void* pHBA, int opcode);
826int CpqTsDestroyTachLiteQues( void* , int);
827int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2);
828
829int CpqTsProcessIMQEntry(void* pHBA);
830int CpqTsResetTachLite(void *pHBA, int type);
831void CpqTsFreezeTachlite(void *pHBA, int type);
832void CpqTsUnFreezeTachlite(void *pHBA, int type);
833int CpqTsInitializeFrameManager(void *pHBA, int);
834int CpqTsLaserControl( void* addrBase, int opcode );
835int CpqTsReadWriteWWN(void*, int ReadWrite);
836int CpqTsReadWriteNVRAM(void*, void* data, int ReadWrite);
837
838void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter);
839void cpqfcTSWorkerThread( void *host);
840
841int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf );
842ULONG cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count,
843 UCHAR *buf );
844
845BOOLEAN tl_write_i2c_nvram( void* GPIOin, void* GPIOout,
846 USHORT startOffset, // e.g. 0x2f for WWN start
847 USHORT count,
848 UCHAR *buf );
849
850
851// define misc functions
852int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[]);
853int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[]);
854void* fcMemManager( struct pci_dev *pdev,
855 ALIGNED_MEM *dyn_mem_pair, ULONG n_alloc, ULONG ab,
856 ULONG ulAlignedAddress, dma_addr_t *dma_handle);
857
858void BigEndianSwap( UCHAR *source, UCHAR *dest, USHORT cnt);
859
860//ULONG virt_to_phys( PVOID virtaddr );
861
862
863// Linux interrupt handler
864irqreturn_t cpqfcTS_intr_handler( int irq,void *dev_id,struct pt_regs *regs);
865void cpqfcTSheartbeat( unsigned long ptr );
866
867
868
869// The biggest Q element we deal with is Aborts - we
870// need 4 bytes for x_ID, and a Scsi_Cmnd (~284 bytes)
871//#define LINKQ_ITEM_SIZE ((4+sizeof(Scsi_Cmnd)+3)/4)
872#define LINKQ_ITEM_SIZE (3*16)
873typedef struct
874{
875 ULONG Type; // e.g. LINKUP, SFQENTRY, PDISC, BLS_ABTS, ...
876 ULONG ulBuff[ LINKQ_ITEM_SIZE ];
877} LINKQ_ITEM;
878
879#define FC_LINKQ_DEPTH TACH_MAX_XID
880typedef struct
881{
882 ULONG producer;
883 ULONG consumer; // when producer equals consumer, Q empty
884
885 LINKQ_ITEM Qitem[ FC_LINKQ_DEPTH ];
886
887} FC_LINK_QUE, *PFC_LINK_QUE;
888
889
890 // DPC routines post to here on Inbound SCSI frames
891 // User thread processes
892#define FC_SCSIQ_DEPTH 32
893
894typedef struct
895{
896 int Type; // e.g. SCSI
897 ULONG ulBuff[ 3*16 ];
898} SCSIQ_ITEM;
899
900typedef struct
901{
902 ULONG producer;
903 ULONG consumer; // when producer equals consumer, Q empty
904
905 SCSIQ_ITEM Qitem[ FC_SCSIQ_DEPTH ];
906
907} FC_SCSI_QUE, *PFC_SCSI_QUE;
908
909typedef struct {
910 /* This is tacked on to a Scsi_Request in upper_private_data
911 for pasthrough ioctls, as a place to hold data that can't
912 be stashed anywhere else in the Scsi_Request. We differentiate
913 this from _real_ upper_private_data by checking if the virt addr
914 is within our special pool. */
915 ushort bus;
916 ushort pdrive;
917} cpqfc_passthru_private_t;
918
919#define CPQFC_MAX_PASSTHRU_CMDS 100
920
921#define DYNAMIC_ALLOCATIONS 4 // Tachyon aligned allocations: ERQ,IMQ,SFQ,SEST
922
923// Linux space allocated per HBA (chip state, etc.)
924typedef struct
925{
926 struct Scsi_Host *HostAdapter; // back pointer to Linux Scsi struct
927
928 TACHYON fcChip; // All Tachyon registers, Queues, functions
929 ALIGNED_MEM dynamic_mem[DYNAMIC_ALLOCATIONS];
930
931 struct pci_dev *PciDev;
932 dma_addr_t fcLQ_dma_handle;
933
934 Scsi_Cmnd *LinkDnCmnd[CPQFCTS_REQ_QUEUE_LEN]; // collects Cmnds during LDn
935 // (for Acceptable targets)
936 Scsi_Cmnd *BoardLockCmnd[CPQFCTS_REQ_QUEUE_LEN]; // SEST was full
937
938 Scsi_Cmnd *BadTargetCmnd[CPQFCTS_MAX_TARGET_ID]; // missing targets
939
940 u_char HBAnum; // 0-based host number
941
942
943 struct timer_list cpqfcTStimer; // FC utility timer for implicit
944 // logouts, FC protocol timeouts, etc.
945 int fcStatsTime; // Statistics delta reporting time
946
947 struct task_struct *worker_thread; // our kernel thread
948 int PortDiscDone; // set by SendLogins(), cleared by LDn
949
950 struct semaphore *TachFrozen;
951 struct semaphore *TYOBcomplete; // handshake for Tach outbound frames
952 struct semaphore *fcQueReady; // FibreChannel work for our kernel thread
953 struct semaphore *notify_wt; // synchronizes kernel thread kill
954 struct semaphore *BoardLock;
955
956 PFC_LINK_QUE fcLQ; // the WorkerThread operates on this
957
958 spinlock_t hba_spinlock; // held/released by WorkerThread
959 cpqfc_passthru_private_t *private_data_pool;
960 unsigned long *private_data_bits;
961
962} CPQFCHBA;
963
964#define CPQ_SPINLOCK_HBA( x ) spin_lock(&x->hba_spinlock);
965#define CPQ_SPINUNLOCK_HBA(x) spin_unlock(&x->hba_spinlock);
966
967
968
969void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
970 PFC_LOGGEDIN_PORT pFcPort);
971
972
973void cpqfcTSTerminateExchange( CPQFCHBA*, SCSI_NEXUS *target, int );
974
975PFC_LOGGEDIN_PORT fcPortLoggedIn(
976 CPQFCHBA *cpqfcHBAdata,
977 TachFCHDR_GCMND* fchs,
978 BOOLEAN,
979 BOOLEAN);
980void fcProcessLoggedIn(
981 CPQFCHBA *cpqfcHBAdata, TachFCHDR_GCMND* fchs);
982
983
984ULONG cpqfcTSBuildExchange(
985 CPQFCHBA *cpqfcHBAdata,
986 ULONG type, // e.g. PLOGI
987 TachFCHDR_GCMND* InFCHS, // incoming FCHS
988 void *Data, // the CDB, scatter/gather, etc.
989 LONG *ExchangeID ); // allocated exchange ID
990
991ULONG cpqfcTSStartExchange(
992 CPQFCHBA *cpqfcHBAdata,
993 LONG ExchangeID );
994
995void cpqfcTSCompleteExchange(
996 struct pci_dev *pcidev,
997 PTACHYON fcChip,
998 ULONG exchange_ID);
999
1000
1001PFC_LOGGEDIN_PORT fcFindLoggedInPort(
1002 PTACHYON fcChip,
1003 Scsi_Cmnd *Cmnd, // (We want the channel/target/lun Nexus from Cmnd)
1004 ULONG port_id, // search linked list for al_pa, or
1005 UCHAR wwn[8], // search linked list for WWN, or...
1006 PFC_LOGGEDIN_PORT *pLastLoggedInPort
1007);
1008
1009void cpqfcTSPutLinkQue(
1010 CPQFCHBA *cpqfcHBAdata,
1011 int Type,
1012 void *QueContent);
1013
1014void fcPutScsiQue(
1015 CPQFCHBA *cpqfcHBAdata,
1016 int Type,
1017 void *QueContent);
1018
1019void fcLinkQReset(
1020 CPQFCHBA *);
1021void fcScsiQReset(
1022 CPQFCHBA *);
1023void fcSestReset(
1024 CPQFCHBA *);
1025
1026void cpqfc_pci_unmap(struct pci_dev *pcidev,
1027 Scsi_Cmnd *cmd,
1028 PTACHYON fcChip,
1029 ULONG x_ID);
1030
1031extern const UCHAR valid_al_pa[];
1032extern const int number_of_al_pa;
1033
1034#define FCP_RESID_UNDER 0x80000
1035#define FCP_RESID_OVER 0x40000
1036#define FCP_SNS_LEN_VALID 0x20000
1037#define FCP_RSP_LEN_VALID 0x10000
1038
1039// RSP_CODE definitions (dpANS Fibre Channel Protocol for SCSI, pg 34)
1040#define FCP_DATA_LEN_NOT_BURST_LEN 0x1000000
1041#define FCP_CMND_FIELD_INVALID 0x2000000
1042#define FCP_DATA_RO_NOT_XRDY_RO 0x3000000
1043#define FCP_TASKFUNCTION_NS 0x4000000
1044#define FCP_TASKFUNCTION_FAIL 0x5000000
1045
1046// FCP-SCSI response status struct
1047typedef struct // see "TachFCHDR_RSP" definition - 64 bytes
1048{
1049 __u32 reserved;
1050 __u32 reserved1;
1051 __u32 fcp_status; // field validity and SCSI status
1052 __u32 fcp_resid;
1053 __u32 fcp_sns_len; // length of FCP_SNS_INFO field
1054 __u32 fcp_rsp_len; // length of FCP_RSP_INFO field (expect 8)
1055 __u32 fcp_rsp_info; // 4 bytes of FCP protocol response information
1056 __u32 fcp_rsp_info2; // (4 more bytes, since most implementations use 8)
1057 __u8 fcp_sns_info[36]; // bytes for SCSI sense (ASC, ASCQ)
1058
1059} FCP_STATUS_RESPONSE, *PFCP_STATUS_RESPONSE;
1060
1061
1062// Fabric State Change Registration
1063typedef struct scrpl
1064{
1065 __u32 command;
1066 __u32 function;
1067} SCR_PL;
1068
1069// Fabric Name Service Request
1070typedef struct nsrpl
1071{
1072 __u32 CT_Rev; // (& IN_ID) WORD 0
1073 __u32 FCS_Type; // WORD 1
1074 __u32 Command_code; // WORD 2
1075 __u32 reason_code; // WORD 3
1076 __u32 FCP; // WORD 4 (lower byte)
1077
1078} NSR_PL;
1079
1080
1081
1082// "FC.H"
1083#define MAX_RX_SIZE 0x800 // Max Receive Buffer Size is 2048
1084#define MIN_RX_SIZE 0x100 // Min Size is 256, per FC-PLDA Spec
1085#define MAX_TARGET_RXIDS SEST_DEPTH
1086#define TARGET_RX_SIZE SEST_BUFFER_LENGTH
1087
1088#define CLASS_1 0x01
1089#define CLASS_2 0x02
1090#define CLASS_3 0x03
1091
1092#define FC_PH42 0x08
1093#define FC_PH43 0x09
1094#define FC_PH3 0x20
1095
1096#define RR_TOV 2 // Minimum Time for target to wait for
1097 // PDISC after a LIP.
1098#define E_D_TOV 2 // Minimum Time to wait for Sequence
1099 // Completion.
1100#define R_A_TOV 0 // Minimum Time for Target to wait
1101 // before reclaiming resources.
1102//
1103// R_CTL Field
1104//
1105// Routing Bits (31-28)
1106//
1107#define FC4_DEVICE_DATA 0x00000000
1108#define EXT_LINK_DATA 0x20000000
1109#define FC4_LINK_DATA 0x30000000
1110#define VIDEO_DATA 0x40000000
1111#define BASIC_LINK_DATA 0x80000000
1112#define LINK_CONTROL 0xC0000000
1113#define ROUTING_MASK 0xF0000000
1114
1115//
1116// Information Bits (27-24)
1117//
1118#define UNCAT_INFORMATION 0x00000000
1119#define SOLICITED_DATA 0x01000000
1120#define UNSOLICITED_CONTROL 0x02000000
1121#define SOLICITED_CONTROL 0x03000000
1122#define UNSOLICITED_DATA 0x04000000
1123#define DATA_DESCRIPTOR 0x05000000
1124#define UNSOLICITED_COMMAND 0x06000000
1125#define COMMAND_STATUS 0x07000000
1126#define INFO_MASK 0x0F000000
1127//
1128// (Link Control Codes)
1129//
1130#define ACK_1 0x00000000
1131#define ACK_0_OR_N 0x01000000
1132#define P_RJT 0x02000000
1133#define F_RJT 0x03000000
1134#define P_BSY 0x04000000
1135#define FABRIC_BUSY_TO_DF 0x05000000 // Fabric Busy to Data Frame
1136#define FABRIC_BUSY_TO_LC 0x06000000 // Fabric Busy to Link Ctl Frame
1137#define LINK_CREDIT_RESET 0x07000000
1138//
1139// (Link Service Command Codes)
1140//
1141//#define LS_RJT 0x01000000 // LS Reject
1142
1143#define LS_ACC 0x02000000 // LS Accept
1144#define LS_PLOGI 0x03000000 // N_PORT Login
1145#define LS_FLOGI 0x04000000 // F_PORT Login
1146#define LS_LOGO 0x05000000 // Logout
1147#define LS_ABTX 0x06000000 // Abort Exchange
1148#define LS_RCS 0x07000000 // Read Connection Status
1149#define LS_RES 0x08000000 // Read Exchange Status
1150#define LS_RSS 0x09000000 // Read Sequence Status
1151#define LS_RSI 0x0A000000 // Request Seq Initiative
1152#define LS_ESTS 0x0B000000 // Establish Steaming
1153#define LS_ESTC 0x0C000000 // Estimate Credit
1154#define LS_ADVC 0x0D000000 // Advice Credit
1155#define LS_RTV 0x0E000000 // Read Timeout Value
1156#define LS_RLS 0x0F000000 // Read Link Status
1157#define LS_ECHO 0x10000000 // Echo
1158#define LS_TEST 0x11000000 // Test
1159#define LS_RRQ 0x12000000 // Reinstate Rec. Qual.
1160#define LS_PRLI 0x20000000 // Process Login
1161#define LS_PRLO 0x21000000 // Process Logout
1162#define LS_TPRLO 0x24000000 // 3rd Party Process Logout
1163#define LS_PDISC 0x50000000 // Process Discovery
1164#define LS_FDISC 0x51000000 // Fabric Discovery
1165#define LS_ADISC 0x52000000 // Discover Address
1166#define LS_RNC 0x53000000 // Report Node Capability
1167#define LS_SCR 0x62000000 // State Change Registration
1168#define LS_MASK 0xFF000000
1169
1170//
1171// TYPE Bit Masks
1172//
1173#define BASIC_LINK_SERVICE 0x00000000
1174#define EXT_LINK_SERVICE 0x01000000
1175
1176#define LLC 0x04000000
1177#define LLC_SNAP 0x05000000
1178#define SCSI_FCP 0x08000000
1179#define SCSI_GPP 0x09000000
1180#define IPI3_MASTER 0x11000000
1181#define IPI3_SLAVE 0x12000000
1182#define IPI3_PEER 0x13000000
1183#define CP_IPI3_MASTER 0x15000000
1184#define CP_IPI3_SLAVE 0x16000000
1185#define CP_IPI3_PEER 0x17000000
1186#define SBCCS_CHANNEL 0x19000000
1187#define SBCCS_CONTROL 0x1A000000
1188#define FIBRE_SERVICES 0x20000000
1189#define FC_FG 0x21000000
1190#define FC_XS 0x22000000
1191#define FC_AL 0x23000000
1192#define SNMP 0x24000000
1193#define HIPPI_FP 0x40000000
1194#define TYPE_MASK 0xFF000000
1195
1196typedef struct {
1197 UCHAR seq_id_valid;
1198 UCHAR seq_id;
1199 USHORT reserved; // 2 bytes reserved
1200 ULONG ox_rx_id;
1201 USHORT low_seq_cnt;
1202 USHORT high_seq_cnt;
1203} BA_ACC_PAYLOAD;
1204
1205typedef struct {
1206 UCHAR reserved;
1207 UCHAR reason_code;
1208 UCHAR reason_explain;
1209 UCHAR vendor_unique;
1210} BA_RJT_PAYLOAD;
1211
1212
1213typedef struct {
1214 ULONG command_code;
1215 ULONG sid;
1216 USHORT ox_id;
1217 USHORT rx_id;
1218} RRQ_MESSAGE;
1219
1220typedef struct {
1221 ULONG command_code;
1222 UCHAR vendor;
1223 UCHAR explain;
1224 UCHAR reason;
1225 UCHAR reserved;
1226} REJECT_MESSAGE;
1227
1228
1229#define N_OR_F_PORT 0x1000
1230#define RANDOM_RELATIVE_OFFSET 0x4000
1231#define CONTINUOSLY_INCREASING 0x8000
1232
1233#define CLASS_VALID 0x8000
1234#define INTERMIX_MODE 0x4000
1235#define TRANSPARENT_STACKED 0x2000
1236#define LOCKDOWN_STACKED 0x1000
1237#define SEQ_DELIVERY 0x800
1238
1239#define XID_NOT_SUPPORTED 0x00
1240#define XID_SUPPORTED 0x4000
1241#define XID_REQUIRED 0xC000
1242
1243#define ASSOCIATOR_NOT_SUPPORTED 0x00
1244#define ASSOCIATOR_SUPPORTED 0x1000
1245#define ASSOCIATOR_REQUIRED 0x3000
1246
1247#define INIT_ACK0_SUPPORT 0x800
1248#define INIT_ACKN_SUPPORT 0x400
1249
1250#define RECIP_ACK0_SUPPORT 0x8000
1251#define RECIP_ACKN_SUPPORT 0x4000
1252
1253#define X_ID_INTERLOCK 0x2000
1254
1255#define ERROR_POLICY 0x1800 // Error Policy Supported
1256#define ERROR_DISCARD 0x00 // Only Discard Supported
1257#define ERROR_DISC_PROCESS 0x02 // Discard and process supported
1258
1259#define NODE_ID 0x01
1260#define IEEE_EXT 0x20
1261
1262//
1263// Categories Supported Per Sequence
1264//
1265#define CATEGORIES_PER_SEQUENCE 0x300
1266#define ONE_CATEGORY_SEQUENCE 0x00 // 1 Category per Sequence
1267#define TWO_CATEGORY_SEQUENCE 0x01 // 2 Categories per Sequence
1268#define MANY_CATEGORY_SEQUENCE 0x03 // > 2 Categories/Sequence
1269
1270typedef struct {
1271
1272 USHORT initiator_control;
1273 USHORT service_options;
1274
1275 USHORT rx_data_size;
1276 USHORT recipient_control;
1277
1278 USHORT ee_credit;
1279 USHORT concurrent_sequences;
1280
1281 USHORT reserved;
1282 USHORT open_sequences;
1283
1284} CLASS_PARAMETERS;
1285
1286typedef struct {
1287 ULONG login_cmd;
1288 //
1289 // Common Service Parameters
1290 //
1291 struct {
1292
1293 USHORT bb_credit;
1294 UCHAR lowest_ver;
1295 UCHAR highest_ver;
1296
1297 USHORT bb_rx_size;
1298 USHORT common_features;
1299
1300 USHORT rel_offset;
1301 USHORT concurrent_seq;
1302
1303
1304 ULONG e_d_tov;
1305 } cmn_services;
1306
1307 //
1308 // Port Name
1309 //
1310 UCHAR port_name[8];
1311
1312 //
1313 // Node/Fabric Name
1314 //
1315 UCHAR node_name[8];
1316
1317 //
1318 // Class 1, 2 and 3 Service Parameters
1319 //
1320 CLASS_PARAMETERS class1;
1321 CLASS_PARAMETERS class2;
1322 CLASS_PARAMETERS class3;
1323
1324 ULONG reserved[4];
1325
1326 //
1327 // Vendor Version Level
1328 //
1329 UCHAR vendor_id[2];
1330 UCHAR vendor_version[6];
1331 ULONG buffer_size;
1332 USHORT rxid_start;
1333 USHORT total_rxids;
1334} LOGIN_PAYLOAD;
1335
1336
1337typedef struct
1338{
1339 ULONG cmd; // 4 bytes
1340 UCHAR n_port_identifier[3];
1341 UCHAR reserved;
1342 UCHAR port_name[8];
1343} LOGOUT_PAYLOAD;
1344
1345
1346//
1347// PRLI Request Service Parameter Defines
1348//
1349#define PRLI_ACC 0x01
1350#define PRLI_REQ 0x02
1351#define ORIG_PROCESS_ASSOC_VALID 0x8000
1352#define RESP_PROCESS_ASSOC_VALID 0x4000
1353#define ESTABLISH_PAIR 0x2000
1354#define DATA_OVERLAY_ALLOWED 0x40
1355#define INITIATOR_FUNCTION 0x20
1356#define TARGET_FUNCTION 0x10
1357#define CMD_DATA_MIXED 0x08
1358#define DATA_RESP_MIXED 0x04
1359#define READ_XFER_RDY 0x02
1360#define WRITE_XFER_RDY 0x01
1361
1362#define RESPONSE_CODE_MASK 0xF00
1363#define REQUEST_EXECUTED 0x100
1364#define NO_RESOURCES 0x200
1365#define INIT_NOT_COMPLETE 0x300
1366#define IMAGE_DOES_NOT_EXIST 0x400
1367#define BAD_PREDEFINED_COND 0x500
1368#define REQ_EXEC_COND 0x600
1369#define NO_MULTI_PAGE 0x700
1370
1371typedef struct {
1372 USHORT payload_length;
1373 UCHAR page_length;
1374 UCHAR cmd;
1375
1376
1377 ULONG valid;
1378
1379 ULONG orig_process_associator;
1380
1381 ULONG resp_process_associator;
1382
1383 ULONG fcp_info;
1384} PRLI_REQUEST;
1385
1386typedef struct {
1387
1388 USHORT payload_length;
1389 UCHAR page_length;
1390 UCHAR cmd;
1391
1392 ULONG valid;
1393 ULONG orig_process_associator;
1394
1395 ULONG resp_process_associator;
1396 ULONG reserved;
1397} PRLO_REQUEST;
1398
1399typedef struct {
1400 ULONG cmd;
1401
1402 ULONG hard_address;
1403
1404 UCHAR port_name[8];
1405
1406 UCHAR node_name[8];
1407
1408 ULONG s_id;
1409} ADISC_PAYLOAD;
1410
1411struct ext_sg_entry_t {
1412 __u32 len:18; /* buffer length, bits 0-17 */
1413 __u32 uba:13; /* upper bus address bits 18-31 */
1414 __u32 lba; /* lower bus address bits 0-31 */
1415};
1416
1417
1418// J. McCarty's LINK.H
1419//
1420// LS_RJT Reason Codes
1421//
1422
1423#define INVALID_COMMAND_CODE 0x01
1424#define LOGICAL_ERROR 0x03
1425#define LOGICAL_BUSY 0x05
1426#define PROTOCOL_ERROR 0x07
1427#define UNABLE_TO_PERFORM 0x09
1428#define COMMAND_NOT_SUPPORTED 0x0B
1429#define LS_VENDOR_UNIQUE 0xFF
1430
1431//
1432// LS_RJT Reason Codes Explanations
1433//
1434#define NO_REASON 0x00
1435#define OPTIONS_ERROR 0x01
1436#define INITIATOR_CTL_ERROR 0x03
1437#define RECIPIENT_CTL_ERROR 0x05
1438#define DATA_FIELD_SIZE_ERROR 0x07
1439#define CONCURRENT_SEQ_ERROR 0x09
1440#define CREDIT_ERROR 0x0B
1441#define INVALID_PORT_NAME 0x0D
1442#define INVALID_NODE_NAME 0x0E
1443#define INVALID_CSP 0x0F // Invalid Service Parameters
1444#define INVALID_ASSOC_HDR 0x11 // Invalid Association Header
1445#define ASSOC_HDR_REQUIRED 0x13 // Association Header Required
1446#define LS_INVALID_S_ID 0x15
1447#define INVALID_OX_RX_ID 0x17 // Invalid OX_ID RX_ID Combination
1448#define CMD_IN_PROCESS 0x19
1449#define INVALID_IDENTIFIER 0x1F // Invalid N_PORT Identifier
1450#define INVALID_SEQ_ID 0x21
1451#define ABT_INVALID_XCHNG 0x23 // Attempt to Abort an invalid Exchange
1452#define ABT_INACTIVE_XCHNG 0x25 // Attempt to Abort an inactive Exchange
1453#define NEED_REC_QUAL 0x27 // Recovery Qualifier required
1454#define NO_LOGIN_RESOURCES 0x29 // No resources to support login
1455#define NO_DATA 0x2A // Unable to supply requested data
1456#define REQUEST_NOT_SUPPORTED 0x2C // Request Not Supported
1457
1458//
1459// Link Control Codes
1460//
1461
1462//
1463// P_BSY Action Codes
1464//
1465#define SEQUENCE_TERMINATED 0x01000000
1466#define SEQUENCE_ACTIVE 0x02000000
1467
1468//
1469// P_BSY Reason Codes
1470//
1471#define PHYS_NPORT_BUSY 0x010000
1472#define NPORT_RESOURCE_BUSY 0x020000
1473
1474//
1475// P_RJT, F_RJT Action Codes
1476//
1477
1478#define RETRYABLE_ERROR 0x01000000
1479#define NON_RETRYABLE_ERROR 0x02000000
1480
1481//
1482// P_RJT, F_RJT Reason Codes
1483//
1484#define INVALID_D_ID 0x010000
1485#define INVALID_S_ID 0x020000
1486#define NPORT_NOT_AVAIL_TMP 0x030000
1487#define NPORT_NOT_AVAIL_PERM 0x040000
1488#define CLASS_NOT_SUPPORTED 0x050000
1489#define USAGE_ERROR 0x060000
1490#define TYPE_NOT_SUPPORTED 0x070000
1491#define INVAL_LINK_CONTROL 0x080000
1492#define INVAL_R_CTL 0x090000
1493#define INVAL_F_CTL 0x0A0000
1494#define INVAL_OX_ID 0x0B0000
1495#define INVAL_RX_ID 0x0C0000
1496#define INVAL_SEQ_ID 0x0D0000
1497#define INVAL_DF_CTL 0x0E0000
1498#define INVAL_SEQ_CNT 0x0F0000
1499#define INVAL_PARAMS 0x100000
1500#define EXCHANGE_ERROR 0x110000
1501#define LS_PROTOCOL_ERROR 0x120000
1502#define INCORRECT_LENGTH 0x130000
1503#define UNEXPECTED_ACK 0x140000
1504#define LOGIN_REQ 0x160000
1505#define EXCESSIVE_SEQ 0x170000
1506#define NO_EXCHANGE 0x180000
1507#define SEC_HDR_NOT_SUPPORTED 0x190000
1508#define NO_FABRIC 0x1A0000
1509#define P_VENDOR_UNIQUE 0xFF0000
1510
1511//
1512// BA_RJT Reason Codes
1513//
1514#define BA_INVALID_COMMAND 0x00010000
1515#define BA_LOGICAL_ERROR 0x00030000
1516#define BA_LOGICAL_BUSY 0x00050000
1517#define BA_PROTOCOL_ERROR 0x00070000
1518#define BA_UNABLE_TO_PERFORM 0x00090000
1519
1520//
1521// BA_RJT Reason Explanation Codes
1522//
1523#define BA_NO_REASON 0x00000000
1524#define BA_INVALID_OX_RX 0x00000300
1525#define BA_SEQUENCE_ABORTED 0x00000500
1526
1527
1528
1529#endif /* CPQFCTSSTRUCTS_H */
1530
diff --git a/drivers/scsi/cpqfcTStrigger.c b/drivers/scsi/cpqfcTStrigger.c
deleted file mode 100644
index dbb7e65159a0..000000000000
--- a/drivers/scsi/cpqfcTStrigger.c
+++ /dev/null
@@ -1,33 +0,0 @@
1// Routine to trigger Finisar GTA analyzer. Runs of GPIO2
2// NOTE: DEBUG ONLY! Could interfere with FCMNGR/Miniport operation
3// since it writes directly to the Tachyon board. This function
4// developed for Compaq HBA Tachyon TS v1.2 (Rev X5 PCB)
5
6#include "cpqfcTStrigger.h"
7#if TRIGGERABLE_HBA
8
9#include <linux/kernel.h>
10#include <linux/ioport.h>
11#include <linux/types.h>
12#include <linux/pci.h>
13#include <asm/io.h>
14
15void TriggerHBA( void* IOBaseUpper, int Print)
16{
17 __u32 long value;
18
19 // get initial value in hopes of not modifying any other GPIO line
20 IOBaseUpper += 0x188; // TachTL/TS Control reg
21
22 value = readl( IOBaseUpper);
23 // set HIGH to trigger external analyzer (tested on Dolche Finisar 1Gb GTA)
24 // The Finisar anaylzer triggers on low-to-high TTL transition
25 value |= 0x01; // set bit 0
26
27 writel( value, IOBaseUpper);
28
29 if( Print)
30 printk( " -GPIO0 set- ");
31}
32
33#endif
diff --git a/drivers/scsi/cpqfcTStrigger.h b/drivers/scsi/cpqfcTStrigger.h
deleted file mode 100644
index c961792e6be0..000000000000
--- a/drivers/scsi/cpqfcTStrigger.h
+++ /dev/null
@@ -1,8 +0,0 @@
1// don't do this unless you have the right hardware!
2#define TRIGGERABLE_HBA 0
3#if TRIGGERABLE_HBA
4void TriggerHBA( void*, int);
5#else
6#define TriggerHBA(x, y)
7#endif
8
diff --git a/drivers/scsi/cpqfcTSworker.c b/drivers/scsi/cpqfcTSworker.c
deleted file mode 100644
index d822ddcc52b2..000000000000
--- a/drivers/scsi/cpqfcTSworker.c
+++ /dev/null
@@ -1,6516 +0,0 @@
1/* Copyright(c) 2000, Compaq Computer Corporation
2 * Fibre Channel Host Bus Adapter
3 * 64-bit, 66MHz PCI
4 * Originally developed and tested on:
5 * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ...
6 * SP# P225CXCBFIEL6T, Rev XC
7 * SP# 161290-001, Rev XD
8 * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
13 * later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 * Written by Don Zimmerman
20*/
21
22#include <linux/sched.h>
23#include <linux/timer.h>
24#include <linux/string.h>
25#include <linux/slab.h>
26#include <linux/ioport.h>
27#include <linux/kernel.h>
28#include <linux/stat.h>
29#include <linux/blkdev.h>
30#include <linux/interrupt.h>
31#include <linux/delay.h>
32#include <linux/smp_lock.h>
33#include <linux/pci.h>
34
35#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
36
37#include <asm/system.h>
38#include <asm/irq.h>
39#include <asm/dma.h>
40
41#include "scsi.h"
42#include <scsi/scsi_host.h> // struct Scsi_Host definition for T handler
43#include "cpqfcTSchip.h"
44#include "cpqfcTSstructs.h"
45#include "cpqfcTStrigger.h"
46
47//#define LOGIN_DBG 1
48
49// REMARKS:
50// Since Tachyon chips may be permitted to wait from 500ms up to 2 sec
51// to empty an outgoing frame from its FIFO to the Fibre Channel stream,
52// we cannot do everything we need to in the interrupt handler. Specifically,
53// every time a link re-init (e.g. LIP) takes place, all SCSI I/O has to be
54// suspended until the login sequences have been completed. Login commands
55// are frames just like SCSI commands are frames; they are subject to the same
56// timeout issues and delays. Also, various specs provide up to 2 seconds for
57// devices to log back in (i.e. respond with ACC to a login frame), so I/O to
58// that device has to be suspended.
59// A serious problem here occurs on highly loaded FC-AL systems. If our FC port
60// has a low priority (e.g. high arbitrated loop physical address, alpa), and
61// some other device is hogging bandwidth (permissible under FC-AL), we might
62// time out thinking the link is hung, when it's simply busy. Many such
63// considerations complicate the design. Although Tachyon assumes control
64// (in silicon) for many link-specific issues, the Linux driver is left with the
65// rest, which turns out to be a difficult, time critical chore.
66
67// These "worker" functions will handle things like FC Logins; all
68// processes with I/O to our device must wait for the Login to complete
69// and (if successful) I/O to resume. In the event of a malfunctioning or
70// very busy loop, it may take hundreds of millisecs or even seconds to complete
71// a frame send. We don't want to hang up the entire server (and all
72// processes which don't depend on Fibre) during this wait.
73
74// The Tachyon chip can have around 30,000 I/O operations ("exchanges")
75// open at one time. However, each exchange must be initiated
76// synchronously (i.e. each of the 30k I/O had to be started one at a
77// time by sending a starting frame via Tachyon's outbound que).
78
79// To accommodate kernel "module" build, this driver limits the exchanges
80// to 256, because of the contiguous physical memory limitation of 128M.
81
82// Typical FC Exchanges are opened presuming the FC frames start without errors,
83// while Exchange completion is handled in the interrupt handler. This
84// optimizes performance for the "everything's working" case.
85// However, when we have FC related errors or hot plugging of FC ports, we pause
86// I/O and handle FC-specific tasks in the worker thread. These FC-specific
87// functions will handle things like FC Logins and Aborts. As the Login sequence
88// completes to each and every target, I/O can resume to that target.
89
90// Our kernel "worker thread" must share the HBA with threads calling
91// "queuecommand". We define a "BoardLock" semaphore which indicates
92// to "queuecommand" that the HBA is unavailable, and Cmnds are added to a
93// board lock Q. When the worker thread finishes with the board, the board
94// lock Q commands are completed with status causing immediate retry.
95// Typically, the board is locked while Logins are in progress after an
96// FC Link Down condition. When Cmnds are re-queued after board lock, the
97// particular Scsi channel/target may or may not have logged back in. When
98// the device is waiting for login, the "prli" flag is clear, in which case
99// commands are passed to a Link Down Q. Whenever the login finally completes,
100// the LinkDown Q is completed, again with status causing immediate retry.
101// When FC devices are logged in, we build and start FC commands to the
102// devices.
103
104// NOTE!! As of May 2000, kernel 2.2.14, the error recovery logic for devices
105// that never log back in (e.g. physically removed) is NOT completely
106// understood. I've still seen instances of system hangs on failed Write
107// commands (possibly from the ext2 layer?) on device removal. Such special
108// cases need to be evaluated from a system/application view - e.g., how
109// exactly does the system want me to complete commands when the device is
110// physically removed??
111
112// local functions
113
114static void SetLoginFields(
115 PFC_LOGGEDIN_PORT pLoggedInPort,
116 TachFCHDR_GCMND* fchs,
117 BOOLEAN PDisc,
118 BOOLEAN Originator);
119
120static void AnalyzeIncomingFrame(
121 CPQFCHBA *cpqfcHBAdata,
122 ULONG QNdx );
123
124static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds );
125
126static int verify_PLOGI( PTACHYON fcChip,
127 TachFCHDR_GCMND* fchs, ULONG* reject_explain);
128static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain);
129
130static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type);
131static void BuildLinkServicePayload(
132 PTACHYON fcChip, ULONG type, void* payload);
133
134static void UnblockScsiDevice( struct Scsi_Host *HostAdapter,
135 PFC_LOGGEDIN_PORT pLoggedInPort);
136
137static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID);
138
139static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata);
140
141static void RevalidateSEST( struct Scsi_Host *HostAdapter,
142 PFC_LOGGEDIN_PORT pLoggedInPort);
143
144static void IssueReportLunsCommand(
145 CPQFCHBA* cpqfcHBAdata,
146 TachFCHDR_GCMND* fchs);
147
148// (see scsi_error.c comments on kernel task creation)
149
150void cpqfcTSWorkerThread( void *host)
151{
152 struct Scsi_Host *HostAdapter = (struct Scsi_Host*)host;
153 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
154#ifdef PCI_KERNEL_TRACE
155 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
156#endif
157 DECLARE_MUTEX_LOCKED(fcQueReady);
158 DECLARE_MUTEX_LOCKED(fcTYOBcomplete);
159 DECLARE_MUTEX_LOCKED(TachFrozen);
160 DECLARE_MUTEX_LOCKED(BoardLock);
161
162 ENTER("WorkerThread");
163
164 lock_kernel();
165 daemonize("cpqfcTS_wt_%d", HostAdapter->host_no);
166 siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
167
168
169 cpqfcHBAdata->fcQueReady = &fcQueReady; // primary wait point
170 cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete;
171 cpqfcHBAdata->TachFrozen = &TachFrozen;
172
173
174 cpqfcHBAdata->worker_thread = current;
175
176 unlock_kernel();
177
178 if( cpqfcHBAdata->notify_wt != NULL )
179 up( cpqfcHBAdata->notify_wt); // OK to continue
180
181 while(1)
182 {
183 unsigned long flags;
184
185 down_interruptible( &fcQueReady); // wait for something to do
186
187 if (signal_pending(current) )
188 break;
189
190 PCI_TRACE( 0x90)
191 // first, take the IO lock so the SCSI upper layers can't call
192 // into our _quecommand function (this also disables INTs)
193 spin_lock_irqsave( HostAdapter->host_lock, flags); // STOP _que function
194 PCI_TRACE( 0x90)
195
196 CPQ_SPINLOCK_HBA( cpqfcHBAdata)
197 // next, set this pointer to indicate to the _quecommand function
198 // that the board is in use, so it should que the command and
199 // immediately return (we don't actually require the semaphore function
200 // in this driver rev)
201
202 cpqfcHBAdata->BoardLock = &BoardLock;
203
204 PCI_TRACE( 0x90)
205
206 // release the IO lock (and re-enable interrupts)
207 spin_unlock_irqrestore( HostAdapter->host_lock, flags);
208
209 // disable OUR HBA interrupt (keep them off as much as possible
210 // during error recovery)
211 disable_irq( cpqfcHBAdata->HostAdapter->irq);
212
213 // OK, let's process the Fibre Channel Link Q and do the work
214 cpqfcTS_WorkTask( HostAdapter);
215
216 // hopefully, no more "work" to do;
217 // re-enable our INTs for "normal" completion processing
218 enable_irq( cpqfcHBAdata->HostAdapter->irq);
219
220
221 cpqfcHBAdata->BoardLock = NULL; // allow commands to be queued
222 CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
223
224
225 // Now, complete any Cmnd we Q'd up while BoardLock was held
226
227 CompleteBoardLockCmnd( cpqfcHBAdata);
228
229
230 }
231 // hopefully, the signal was for our module exit...
232 if( cpqfcHBAdata->notify_wt != NULL )
233 up( cpqfcHBAdata->notify_wt); // yep, we're outta here
234}
235
236
237// Freeze Tachyon routine.
238// If Tachyon is already frozen, return FALSE
239// If Tachyon is not frozen, call freeze function, return TRUE
240//
241static BOOLEAN FreezeTach( CPQFCHBA *cpqfcHBAdata)
242{
243 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
244 BOOLEAN FrozeTach = FALSE;
245 // It's possible that the chip is already frozen; if so,
246 // "Freezing" again will NOT! generate another Freeze
247 // Completion Message.
248
249 if( (fcChip->Registers.TYstatus.value & 0x70000) != 0x70000)
250 { // (need to freeze...)
251 fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists
252
253 // 2. Get Tach freeze confirmation
254 // (synchronize SEST manipulation with Freeze Completion Message)
255 // we need INTs on so semaphore can be set.
256 enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Semaphore
257 down_interruptible( cpqfcHBAdata->TachFrozen); // wait for INT handler sem.
258 // can we TIMEOUT semaphore wait?? TBD
259 disable_irq( cpqfcHBAdata->HostAdapter->irq);
260
261 FrozeTach = TRUE;
262 } // (else, already frozen)
263
264 return FrozeTach;
265}
266
267
268
269
270// This is the kernel worker thread task, which processes FC
271// tasks which were queued by the Interrupt handler or by
272// other WorkTask functions.
273
274#define DBG 1
275//#undef DBG
276void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter)
277{
278 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
279 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
280 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
281 ULONG QconsumerNdx;
282 LONG ExchangeID;
283 ULONG ulStatus=0;
284 TachFCHDR_GCMND fchs;
285 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
286
287 ENTER("WorkTask");
288
289 // copy current index to work on
290 QconsumerNdx = fcLQ->consumer;
291
292 PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90)
293
294
295 // NOTE: when this switch completes, we will "consume" the Que item
296// printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
297 switch( fcLQ->Qitem[QconsumerNdx].Type )
298 {
299 // incoming frame - link service (ACC, UNSOL REQ, etc.)
300 // or FCP-SCSI command
301 case SFQ_UNKNOWN:
302 AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx );
303
304 break;
305
306
307
308 case EXCHANGE_QUEUED: // an Exchange (i.e. FCP-SCSI) was previously
309 // Queued because the link was down. The
310 // heartbeat timer detected it and Queued it here.
311 // We attempt to start it again, and if
312 // successful we clear the EXCHANGE_Q flag.
313 // If the link doesn't come up, the Exchange
314 // will eventually time-out.
315
316 ExchangeID = (LONG) // x_ID copied from DPC timeout function
317 fcLQ->Qitem[QconsumerNdx].ulBuff[0];
318
319 // It's possible that a Q'd exchange could have already
320 // been started by other logic (e.g. ABTS process)
321 // Don't start if already started (Q'd flag clear)
322
323 if( Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED )
324 {
325// printk(" *Start Q'd x_ID %Xh: type %Xh ",
326// ExchangeID, Exchanges->fcExchange[ExchangeID].type);
327
328 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID);
329 if( !ulStatus )
330 {
331// printk("success* ");
332 }
333 else
334 {
335#ifdef DBG
336
337 if( ulStatus == EXCHANGE_QUEUED)
338 printk("Queued* ");
339 else
340 printk("failed* ");
341
342#endif
343 }
344 }
345 break;
346
347
348 case LINKDOWN:
349 // (lots of things already done in INT handler) future here?
350 break;
351
352
353 case LINKACTIVE: // Tachyon set the Lup bit in FM status
354 // NOTE: some misbehaving FC ports (like Tach2.1)
355 // can re-LIP immediately after a LIP completes.
356
357 // if "initiator", need to verify LOGs with ports
358// printk("\n*LNKUP* ");
359
360 if( fcChip->Options.initiator )
361 SendLogins( cpqfcHBAdata, NULL ); // PLOGI or PDISC, based on fcPort data
362 // if SendLogins successfully completes, PortDiscDone
363 // will be set.
364
365
366 // If SendLogins was successful, then we expect to get incoming
367 // ACCepts or REJECTs, which are handled below.
368
369 break;
370
371 // LinkService and Fabric request/reply processing
372 case ELS_FDISC: // need to send Fabric Discovery (Login)
373 case ELS_FLOGI: // need to send Fabric Login
374 case ELS_SCR: // need to send State Change Registration
375 case FCS_NSR: // need to send Name Service Request
376 case ELS_PLOGI: // need to send PLOGI
377 case ELS_ACC: // send generic ACCept
378 case ELS_PLOGI_ACC: // need to send ELS ACCept frame to recv'd PLOGI
379 case ELS_PRLI_ACC: // need to send ELS ACCept frame to recv'd PRLI
380 case ELS_LOGO: // need to send ELS LOGO (logout)
381 case ELS_LOGO_ACC: // need to send ELS ACCept frame to recv'd PLOGI
382 case ELS_RJT: // ReJecT reply
383 case ELS_PRLI: // need to send ELS PRLI
384
385
386// printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
387 // if PortDiscDone is not set, it means the SendLogins routine
388 // failed to complete -- assume that LDn occurred, so login frames
389 // are invalid
390 if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
391 {
392 printk("Discard Q'd ELS login frame\n");
393 break;
394 }
395
396 ulStatus = cpqfcTSBuildExchange(
397 cpqfcHBAdata,
398 fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
399 (TachFCHDR_GCMND*)
400 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
401 NULL, // no data (no scatter/gather list)
402 &ExchangeID );// fcController->fcExchanges index, -1 if failed
403
404 if( !ulStatus ) // Exchange setup?
405 {
406 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
407 if( !ulStatus )
408 {
409 // submitted to Tach's Outbound Que (ERQ PI incremented)
410 // waited for completion for ELS type (Login frames issued
411 // synchronously)
412 }
413 else
414 // check reason for Exchange not being started - we might
415 // want to Queue and start later, or fail with error
416 {
417
418 }
419 }
420
421 else // Xchange setup failed...
422 printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
423
424 break;
425
426 case SCSI_REPORT_LUNS:
427 // pass the incoming frame (actually, it's a PRLI frame)
428 // so we can send REPORT_LUNS, in order to determine VSA/PDU
429 // FCP-SCSI Lun address mode
430 IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*)
431 fcLQ->Qitem[QconsumerNdx].ulBuff);
432
433 break;
434
435
436
437
438 case BLS_ABTS: // need to ABORT one or more exchanges
439 {
440 LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
441 BOOLEAN FrozeTach = FALSE;
442
443 if ( x_ID >= TACH_SEST_LEN ) // (in)sanity check
444 {
445// printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
446 break;
447 }
448
449
450 if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE
451 {
452// printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
453
454 break; // nothing to abort!
455 }
456
457//#define ABTS_DBG
458#ifdef ABTS_DBG
459 printk("INV SEST[%X] ", x_ID);
460 if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
461 {
462 printk("FC2TO");
463 }
464 if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
465 {
466 printk("IA");
467 }
468 if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
469 {
470 printk("PORTID");
471 }
472 if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)
473 {
474 printk("DEVRM");
475 }
476 if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
477 {
478 printk("LKF");
479 }
480 if( Exchanges->fcExchange[x_ID].status & FRAME_TO)
481 {
482 printk("FRMTO");
483 }
484 if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY)
485 {
486 printk("ABSQ");
487 }
488 if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME)
489 {
490 printk("SFQFR");
491 }
492
493 if( Exchanges->fcExchange[ x_ID].type == 0x2000)
494 printk(" WR");
495 else if( Exchanges->fcExchange[ x_ID].type == 0x3000)
496 printk(" RD");
497 else if( Exchanges->fcExchange[ x_ID].type == 0x10)
498 printk(" ABTS");
499 else
500 printk(" %Xh", Exchanges->fcExchange[ x_ID].type);
501
502 if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT))
503 {
504 printk(" Cmd %p, ",
505 Exchanges->fcExchange[ x_ID].Cmnd);
506
507 printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n",
508 cpqfcHBAdata->HBAnum,
509 Exchanges->fcExchange[ x_ID].Cmnd->channel,
510 Exchanges->fcExchange[ x_ID].Cmnd->target,
511 Exchanges->fcExchange[ x_ID].Cmnd->lun,
512 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
513 }
514 else // assume that Cmnd ptr is invalid on _abort()
515 {
516 printk(" Cmd ptr invalid\n");
517 }
518
519#endif
520
521
522 // Steps to ABORT a SEST exchange:
523 // 1. Freeze TL SCSI assists & ERQ (everything)
524 // 2. Receive FROZEN inbound CM (must succeed!)
525 // 3. Invalidate x_ID SEST entry
526 // 4. Resume TL SCSI assists & ERQ (everything)
527 // 5. Build/start on exchange - change "type" to BLS_ABTS,
528 // timeout to X sec (RA_TOV from PLDA is actually 0)
529 // 6. Set Exchange Q'd status if ABTS cannot be started,
530 // or simply complete Exchange in "Terminate" condition
531
532 PCI_TRACEO( x_ID, 0xB4)
533
534 // 1 & 2 . Freeze Tach & get confirmation of freeze
535 FrozeTach = FreezeTach( cpqfcHBAdata);
536
537 // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
538 // FC2_TIMEOUT means we are originating the abort, while
539 // TARGET_ABORT means we are ACCepting an abort.
540 // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are
541 // all from Tachyon:
542 // Exchange was corrupted by LDn or other FC physical failure
543 // INITIATOR_ABORT means the upper layer driver/application
544 // requested the abort.
545
546
547
548 // clear bit 31 (VALid), to invalidate & take control from TL
549 fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
550
551
552 // examine and Tach's "Linked List" for IWEs that
553 // received (nearly) simultaneous transfer ready (XRDY)
554 // repair linked list if necessary (TBD!)
555 // (If we ignore the "Linked List", we will time out
556 // WRITE commands where we received the FCP-SCSI XFRDY
557 // frame (because Tachyon didn't processes it). Linked List
558 // management should be done as an optimization.
559
560// readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
561
562
563
564
565 // 4. Resume all Tachlite functions (for other open Exchanges)
566 // as quickly as possible to allow other exchanges to other ports
567 // to resume. Freezing Tachyon may cause cascading errors, because
568 // any received SEST frame cannot be processed by the SEST.
569 // Don't "unfreeze" unless Link is operational
570 if( FrozeTach ) // did we just freeze it (above)?
571 fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
572
573
574 PCI_TRACEO( x_ID, 0xB4)
575
576 // Note there is no confirmation that the chip is "unfrozen". Also,
577 // if the Link is down when unfreeze is called, it has no effect.
578 // Chip will unfreeze when the Link is back up.
579
580 // 5. Now send out Abort commands if possible
581 // Some Aborts can't be "sent" (Port_id changed or gone);
582 // if the device is gone, there is no port_id to send the ABTS to.
583
584 if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED)
585 &&
586 !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) )
587 {
588 Exchanges->fcExchange[ x_ID].type = BLS_ABTS;
589 fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id;
590 ulStatus = cpqfcTSBuildExchange(
591 cpqfcHBAdata,
592 BLS_ABTS,
593 &fchs, // (uses only s_id)
594 NULL, // (no scatter/gather list for ABTS)
595 &x_ID );// ABTS on this Exchange ID
596
597 if( !ulStatus ) // Exchange setup build OK?
598 {
599
600 // ABTS may be needed because an Exchange was corrupted
601 // by a Link disruption. If the Link is UP, we can
602 // presume that this ABTS can start immediately; otherwise,
603 // set Que'd status so the Login functions
604 // can restart it when the FC physical Link is restored
605 if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init?
606 {
607// printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
608 Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED;
609 }
610
611 else // what FC device (port_id) does the Cmd belong to?
612 {
613 PFC_LOGGEDIN_PORT pLoggedInPort =
614 Exchanges->fcExchange[ x_ID].pLoggedInPort;
615
616 // if Port is logged in, we might start the abort.
617
618 if( (pLoggedInPort != NULL)
619 &&
620 (pLoggedInPort->prli == TRUE) )
621 {
622 // it's possible that an Exchange has already been Queued
623 // to start after Login completes. Check and don't
624 // start it (again) here if Q'd status set
625// printk(" ABTS xchg %Xh ", x_ID);
626 if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED)
627 {
628// printk("already Q'd ");
629 }
630 else
631 {
632// printk("starting ");
633
634 fcChip->fcStats.FC2aborted++;
635 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
636 if( !ulStatus )
637 {
638 // OK
639 // submitted to Tach's Outbound Que (ERQ PI incremented)
640 }
641 else
642 {
643/* printk("ABTS exchange start failed -status %Xh, x_ID %Xh ",
644 ulStatus, x_ID);
645*/
646 }
647 }
648 }
649 else
650 {
651/* printk(" ABTS NOT starting xchg %Xh, %p ",
652 x_ID, pLoggedInPort);
653 if( pLoggedInPort )
654 printk("prli %d ", pLoggedInPort->prli);
655*/
656 }
657 }
658 }
659 else // what the #@!
660 { // how do we fail to build an Exchange for ABTS??
661 printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n",
662 ulStatus, x_ID);
663 }
664 }
665 else // abort without ABTS -- just complete exchange/Cmnd to Linux
666 {
667// printk(" *Terminating x_ID %Xh on %Xh* ",
668// x_ID, Exchanges->fcExchange[x_ID].status);
669 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, x_ID);
670
671 }
672 } // end of ABTS case
673 break;
674
675
676
677 case BLS_ABTS_ACC: // need to ACCept one ABTS
678 // (NOTE! this code not updated for Linux yet..)
679
680
681 printk(" *ABTS_ACC* ");
682 // 1. Freeze TL
683
684 fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists
685
686 memcpy( // copy the incoming ABTS frame
687 &fchs,
688 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
689 sizeof( fchs));
690
691 // 3. OK, Tachyon is frozen so we can invalidate SEST entry
692 // (if necessary)
693 // Status FC2_TIMEOUT means we are originating the abort, while
694 // TARGET_ABORT means we are ACCepting an abort
695
696 ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
697// printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
698
699
700 // sanity check on received ExchangeID
701 if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT )
702 {
703 // clear bit 31 (VALid), to invalidate & take control from TL
704// printk("Invalidating SEST exchange %Xh\n", ExchangeID);
705 fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
706 }
707
708
709 // 4. Resume all Tachlite functions (for other open Exchanges)
710 // as quickly as possible to allow other exchanges to other ports
711 // to resume. Freezing Tachyon for too long may royally screw
712 // up everything!
713 fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
714
715 // Note there is no confirmation that the chip is "unfrozen". Also,
716 // if the Link is down when unfreeze is called, it has no effect.
717 // Chip will unfreeze when the Link is back up.
718
719 // 5. Now send out Abort ACC reply for this exchange
720 Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC;
721
722 fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id;
723 ulStatus = cpqfcTSBuildExchange(
724 cpqfcHBAdata,
725 BLS_ABTS_ACC,
726 &fchs,
727 NULL, // no data (no scatter/gather list)
728 &ExchangeID );// fcController->fcExchanges index, -1 if failed
729
730 if( !ulStatus ) // Exchange setup?
731 {
732 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
733 if( !ulStatus )
734 {
735 // submitted to Tach's Outbound Que (ERQ PI incremented)
736 // waited for completion for ELS type (Login frames issued
737 // synchronously)
738 }
739 else
740 // check reason for Exchange not being started - we might
741 // want to Queue and start later, or fail with error
742 {
743
744 }
745 }
746 break;
747
748
749 case BLS_ABTS_RJT: // need to ReJecT one ABTS; reject implies the
750 // exchange doesn't exist in the TARGET context.
751 // ExchangeID has to come from LinkService space.
752
753 printk(" *ABTS_RJT* ");
754 ulStatus = cpqfcTSBuildExchange(
755 cpqfcHBAdata,
756 BLS_ABTS_RJT,
757 (TachFCHDR_GCMND*)
758 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
759 NULL, // no data (no scatter/gather list)
760 &ExchangeID );// fcController->fcExchanges index, -1 if failed
761
762 if( !ulStatus ) // Exchange setup OK?
763 {
764 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
765 // If it fails, we aren't required to retry.
766 }
767 if( ulStatus )
768 {
769 printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
770 }
771 else
772 {
773 printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
774
775 }
776
777 break;
778
779
780
781 default:
782 break;
783 } // end switch
784//doNothing:
785 // done with this item - now set the NEXT index
786
787 if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test
788 {
789 fcLQ->consumer = 0;
790 }
791 else
792 {
793 fcLQ->consumer++;
794 }
795
796 PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94)
797
798 LEAVE("WorkTask");
799 return;
800}
801
802
803
804
805// When Tachyon reports link down, bad al_pa, or Link Service (e.g. Login)
806// commands come in, post to the LinkQ so that action can be taken outside the
807// interrupt handler.
808// This circular Q works like Tachyon's que - the producer points to the next
809// (unused) entry. Called by Interrupt handler, WorkerThread, Timer
810// sputlinkq
811void cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata,
812 int Type,
813 void *QueContent)
814{
815 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
816// FC_EXCHANGES *Exchanges = fcChip->Exchanges;
817 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
818 ULONG ndx;
819
820 ENTER("cpqfcTSPutLinkQ");
821
822 ndx = fcLQ->producer;
823
824 ndx += 1; // test for Que full
825
826
827
828 if( ndx >= FC_LINKQ_DEPTH ) // rollover test
829 ndx = 0;
830
831 if( ndx == fcLQ->consumer ) // QUE full test
832 {
833 // QUE was full! lost LK command (fatal to logic)
834 fcChip->fcStats.lnkQueFull++;
835
836 printk("*LinkQ Full!*");
837 TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
838/*
839 {
840 int i;
841 printk("LinkQ PI %d, CI %d\n", fcLQ->producer,
842 fcLQ->consumer);
843
844 for( i=0; i< FC_LINKQ_DEPTH; )
845 {
846 printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
847 if( (++i %8) == 0) printk("\n");
848 }
849
850 }
851*/
852 printk( "cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
853 }
854 else // QUE next element
855 {
856 // Prevent certain multiple (back-to-back) requests.
857 // This is important in that we don't want to issue multiple
858 // ABTS for the same Exchange, or do multiple FM inits, etc.
859 // We can never be sure of the timing of events reported to
860 // us by Tach's IMQ, which can depend on system/bus speeds,
861 // FC physical link circumstances, etc.
862
863 if( (fcLQ->producer != fcLQ->consumer)
864 &&
865 (Type == FMINIT) )
866 {
867 LONG lastNdx; // compute previous producer index
868 if( fcLQ->producer)
869 lastNdx = fcLQ->producer- 1;
870 else
871 lastNdx = FC_LINKQ_DEPTH-1;
872
873
874 if( fcLQ->Qitem[lastNdx].Type == FMINIT)
875 {
876// printk(" *skip FMINIT Q post* ");
877// goto DoneWithPutQ;
878 }
879
880 }
881
882 // OK, add the Q'd item...
883
884 fcLQ->Qitem[fcLQ->producer].Type = Type;
885
886 memcpy(
887 fcLQ->Qitem[fcLQ->producer].ulBuff,
888 QueContent,
889 sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
890
891 fcLQ->producer = ndx; // increment Que producer
892
893 // set semaphore to wake up Kernel (worker) thread
894 //
895 up( cpqfcHBAdata->fcQueReady );
896 }
897
898//DoneWithPutQ:
899
900 LEAVE("cpqfcTSPutLinkQ");
901}
902
903
904
905
906// reset device ext FC link Q
907void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata)
908
909{
910 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
911 fcLQ->producer = 0;
912 fcLQ->consumer = 0;
913
914}
915
916
917
918
919
920// When Tachyon gets an unassisted FCP-SCSI frame, post here so
921// an arbitrary context thread (e.g. IOCTL loopback test function)
922// can process it.
923
924// (NOTE: Not revised for Linux)
925// This Q works like Tachyon's que - the producer points to the next
926// (unused) entry.
927void cpqfcTSPutScsiQue( CPQFCHBA *cpqfcHBAdata,
928 int Type,
929 void *QueContent)
930{
931// CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
932// PTACHYON fcChip = &cpqfcHBAdata->fcChip;
933
934// ULONG ndx;
935
936// ULONG *pExchangeID;
937// LONG ExchangeID;
938
939/*
940 KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);
941 ndx = pDevExt->fcScsiQue.producer + 1; // test for Que full
942
943 if( ndx >= FC_SCSIQ_DEPTH ) // rollover test
944 ndx = 0;
945
946 if( ndx == pDevExt->fcScsiQue.consumer ) // QUE full test
947 {
948 // QUE was full! lost LK command (fatal to logic)
949 fcChip->fcStats.ScsiQueFull++;
950#ifdef DBG
951 printk( "fcPutScsiQue - FULL!\n");
952#endif
953
954 }
955 else // QUE next element
956 {
957 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].Type = Type;
958
959 if( Type == FCP_RSP )
960 {
961 // this TL inbound message type means that a TL SEST exchange has
962 // copied an FCP response frame into a buffer pointed to by the SEST
963 // entry. That buffer is allocated in the SEST structure at ->RspHDR.
964 // Copy the RspHDR for use by the Que handler.
965 pExchangeID = (ULONG *)QueContent;
966
967 memcpy(
968 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
969 &fcChip->SEST->RspHDR[ *pExchangeID ],
970 sizeof(pDevExt->fcScsiQue.Qitem[0].ulBuff)); // (any element for size)
971
972 }
973 else
974 {
975 memcpy(
976 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
977 QueContent,
978 sizeof(pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff));
979 }
980
981 pDevExt->fcScsiQue.producer = ndx; // increment Que
982
983
984 KeSetEvent( &pDevExt->TYIBscsi, // signal any waiting thread
985 0, // no priority boost
986 FALSE ); // no waiting later for this event
987 }
988 KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock);
989*/
990}
991
992
993
994
995
996
997
998static void ProcessELS_Request( CPQFCHBA*,TachFCHDR_GCMND*);
999
1000static void ProcessELS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
1001
1002static void ProcessFCS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
1003
1004void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
1005 PFC_LOGGEDIN_PORT pFcPort)
1006{
1007 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1008
1009 if( pFcPort->port_id != 0xFFFC01 ) // don't care about Fabric
1010 {
1011 fcChip->fcStats.logouts++;
1012 printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n",
1013 (ULONG)pFcPort->u.liWWN,
1014 (ULONG)(pFcPort->u.liWWN >>32),
1015 pFcPort->port_id);
1016
1017 // Terminate I/O with this (Linux) Scsi target
1018 cpqfcTSTerminateExchange( cpqfcHBAdata,
1019 &pFcPort->ScsiNexus,
1020 DEVICE_REMOVED);
1021 }
1022
1023 // Do an "implicit logout" - we can't really Logout the device
1024 // (i.e. with LOGOut Request) because of port_id confusion
1025 // (i.e. the Other port has no port_id).
1026 // A new login for that WWN will have to re-write port_id (0 invalid)
1027 pFcPort->port_id = 0; // invalid!
1028 pFcPort->pdisc = FALSE;
1029 pFcPort->prli = FALSE;
1030 pFcPort->plogi = FALSE;
1031 pFcPort->flogi = FALSE;
1032 pFcPort->LOGO_timer = 0;
1033 pFcPort->device_blocked = TRUE; // block Scsi Requests
1034 pFcPort->ScsiNexus.VolumeSetAddressing=0;
1035}
1036
1037
1038// On FC-AL, there is a chance that a previously known device can
1039// be quietly removed (e.g. with non-managed hub),
1040// while a NEW device (with different WWN) took the same alpa or
1041// even 24-bit port_id. This chance is unlikely but we must always
1042// check for it.
1043static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata,
1044 PFC_LOGGEDIN_PORT pLoggedInPort)
1045{
1046 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1047 // set "other port" at beginning of fcPorts list
1048 PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
1049 while( pOtherPortWithPortId )
1050 {
1051 if( (pOtherPortWithPortId->port_id ==
1052 pLoggedInPort->port_id)
1053 &&
1054 (pOtherPortWithPortId != pLoggedInPort) )
1055 {
1056 // trouble! (Implicitly) Log the other guy out
1057 printk(" *port_id %Xh is duplicated!* ",
1058 pOtherPortWithPortId->port_id);
1059 cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId);
1060 }
1061 pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
1062 }
1063}
1064
1065
1066
1067
1068
1069
1070// Dynamic Memory Allocation for newly discovered FC Ports.
1071// For simplicity, maintain fcPorts structs for ALL
1072// for discovered devices, including those we never do I/O with
1073// (e.g. Fabric addresses)
1074
1075static PFC_LOGGEDIN_PORT CreateFcPort(
1076 CPQFCHBA* cpqfcHBAdata,
1077 PFC_LOGGEDIN_PORT pLastLoggedInPort,
1078 TachFCHDR_GCMND* fchs,
1079 LOGIN_PAYLOAD* plogi)
1080{
1081 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1082 PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
1083 int i;
1084
1085
1086 printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
1087 for( i=3; i>=0; i--) // copy the LOGIN port's WWN
1088 printk("%02X", plogi->port_name[i]);
1089 for( i=7; i>3; i--) // copy the LOGIN port's WWN
1090 printk("%02X", plogi->port_name[i]);
1091
1092
1093 // allocate mem for new port
1094 // (these are small and rare allocations...)
1095 pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC );
1096
1097
1098 // allocation succeeded? Fill out NEW PORT
1099 if( pNextLoggedInPort )
1100 {
1101 // clear out any garbage (sometimes exists)
1102 memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT));
1103
1104
1105 // If we login to a Fabric, we don't want to treat it
1106 // as a SCSI device...
1107 if( (fchs->s_id & 0xFFF000) != 0xFFF000)
1108 {
1109 int i;
1110
1111 // create a unique "virtual" SCSI Nexus (for now, just a
1112 // new target ID) -- we will update channel/target on REPORT_LUNS
1113 // special case for very first SCSI target...
1114 if( cpqfcHBAdata->HostAdapter->max_id == 0)
1115 {
1116 pNextLoggedInPort->ScsiNexus.target = 0;
1117 fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
1118 }
1119 else
1120 {
1121 pNextLoggedInPort->ScsiNexus.target =
1122 cpqfcHBAdata->HostAdapter->max_id;
1123 }
1124
1125 // initialize the lun[] Nexus struct for lun masking
1126 for( i=0; i< CPQFCTS_MAX_LUN; i++)
1127 pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
1128
1129 pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
1130
1131 printk(" SCSI Chan/Trgt %d/%d",
1132 pNextLoggedInPort->ScsiNexus.channel,
1133 pNextLoggedInPort->ScsiNexus.target);
1134
1135 // tell Scsi layers about the new target...
1136 cpqfcHBAdata->HostAdapter->max_id++;
1137// printk("HostAdapter->max_id = %d\n",
1138// cpqfcHBAdata->HostAdapter->max_id);
1139 }
1140 else
1141 {
1142 // device is NOT SCSI (in case of Fabric)
1143 pNextLoggedInPort->ScsiNexus.target = -1; // invalid
1144 }
1145
1146 // create forward link to new port
1147 pLastLoggedInPort->pNextPort = pNextLoggedInPort;
1148 printk("\n");
1149
1150 }
1151 return pNextLoggedInPort; // NULL on allocation failure
1152} // end NEW PORT (WWN) logic
1153
1154
1155
1156// For certain cases, we want to terminate exchanges without
1157// sending ABTS to the device. Examples include when an FC
1158// device changed it's port_id after Loop re-init, or when
1159// the device sent us a logout. In the case of changed port_id,
1160// we want to complete the command and return SOFT_ERROR to
1161// force a re-try. In the case of LOGOut, we might return
1162// BAD_TARGET if the device is really gone.
1163// Since we must ensure that Tachyon is not operating on the
1164// exchange, we have to freeze the chip
1165// sterminateex
1166void cpqfcTSTerminateExchange(
1167 CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus)
1168{
1169 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1170 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1171 ULONG x_ID;
1172
1173 if( ScsiNexus )
1174 {
1175// printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
1176// ScsiNexus->channel, ScsiNexus->target);
1177
1178 }
1179
1180 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
1181 {
1182 if( Exchanges->fcExchange[x_ID].type ) // in use?
1183 {
1184 if( ScsiNexus == NULL ) // our HBA changed - term. all
1185 {
1186 Exchanges->fcExchange[x_ID].status = TerminateStatus;
1187 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID );
1188 }
1189 else
1190 {
1191 // If a device, according to WWN, has been removed, it's
1192 // port_id may be used by another working device, so we
1193 // have to terminate by SCSI target, NOT port_id.
1194 if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
1195 {
1196 if( (Exchanges->fcExchange[x_ID].Cmnd->device->id == ScsiNexus->target)
1197 &&
1198 (Exchanges->fcExchange[x_ID].Cmnd->device->channel == ScsiNexus->channel))
1199 {
1200 Exchanges->fcExchange[x_ID].status = TerminateStatus;
1201 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out
1202 }
1203 }
1204
1205 // (in case we ever need it...)
1206 // all SEST structures have a remote node ID at SEST DWORD 2
1207 // if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
1208 // == port_id)
1209 }
1210 }
1211 }
1212}
1213
1214
1215static void ProcessELS_Request(
1216 CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
1217{
1218 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1219// FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1220// ULONG ox_id = (fchs->ox_rx_id >>16);
1221 PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort;
1222 BOOLEAN NeedReject = FALSE;
1223 ULONG ls_reject_code = 0; // default don'n know??
1224
1225
1226 // Check the incoming frame for a supported ELS type
1227 switch( fchs->pl[0] & 0xFFFF)
1228 {
1229 case 0x0050: // PDISC?
1230
1231 // Payload for PLOGI and PDISC is identical (request & reply)
1232 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
1233 {
1234 LOGIN_PAYLOAD logi; // FC-PH Port Login
1235
1236 // PDISC payload OK. If critical login fields
1237 // (e.g. WWN) matches last login for this port_id,
1238 // we may resume any prior exchanges
1239 // with the other port
1240
1241
1242 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1243
1244 pLoggedInPort = fcFindLoggedInPort(
1245 fcChip,
1246 NULL, // don't search Scsi Nexus
1247 0, // don't search linked list for port_id
1248 &logi.port_name[0], // search linked list for WWN
1249 &pLastLoggedInPort); // must return non-NULL; when a port_id
1250 // is not found, this pointer marks the
1251 // end of the singly linked list
1252
1253 if( pLoggedInPort != NULL) // WWN found (prior login OK)
1254 {
1255
1256 if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
1257 {
1258 // Yes. We were expecting PDISC?
1259 if( pLoggedInPort->pdisc )
1260 {
1261 // Yes; set fields accordingly. (PDISC, not Originator)
1262 SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE);
1263
1264 // send 'ACC' reply
1265 cpqfcTSPutLinkQue( cpqfcHBAdata,
1266 ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1267 fchs );
1268
1269 // OK to resume I/O...
1270 }
1271 else
1272 {
1273 printk("Not expecting PDISC (pdisc=FALSE)\n");
1274 NeedReject = TRUE;
1275 // set reject reason code
1276 ls_reject_code =
1277 LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1278 }
1279 }
1280 else
1281 {
1282 if( pLoggedInPort->port_id != 0)
1283 {
1284 printk("PDISC PortID change: old %Xh, new %Xh\n",
1285 pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
1286 }
1287 NeedReject = TRUE;
1288 // set reject reason code
1289 ls_reject_code =
1290 LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1291
1292 }
1293 }
1294 else
1295 {
1296 printk("PDISC Request from unknown WWN\n");
1297 NeedReject = TRUE;
1298
1299 // set reject reason code
1300 ls_reject_code =
1301 LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME);
1302 }
1303
1304 }
1305 else // Payload unacceptable
1306 {
1307 printk("payload unacceptable\n");
1308 NeedReject = TRUE; // reject code already set
1309
1310 }
1311
1312 if( NeedReject)
1313 {
1314 ULONG port_id;
1315 // The PDISC failed. Set login struct flags accordingly,
1316 // terminate any I/O to this port, and Q a PLOGI
1317 if( pLoggedInPort )
1318 {
1319 pLoggedInPort->pdisc = FALSE;
1320 pLoggedInPort->prli = FALSE;
1321 pLoggedInPort->plogi = FALSE;
1322
1323 cpqfcTSTerminateExchange( cpqfcHBAdata,
1324 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1325 port_id = pLoggedInPort->port_id;
1326 }
1327 else
1328 {
1329 port_id = fchs->s_id &0xFFFFFF;
1330 }
1331 fchs->reserved = ls_reject_code; // borrow this (unused) field
1332 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
1333 }
1334
1335 break;
1336
1337
1338
1339 case 0x0003: // PLOGI?
1340
1341 // Payload for PLOGI and PDISC is identical (request & reply)
1342 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
1343 {
1344 LOGIN_PAYLOAD logi; // FC-PH Port Login
1345 BOOLEAN NeedReject = FALSE;
1346
1347 // PDISC payload OK. If critical login fields
1348 // (e.g. WWN) matches last login for this port_id,
1349 // we may resume any prior exchanges
1350 // with the other port
1351
1352
1353 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1354
1355 pLoggedInPort = fcFindLoggedInPort(
1356 fcChip,
1357 NULL, // don't search Scsi Nexus
1358 0, // don't search linked list for port_id
1359 &logi.port_name[0], // search linked list for WWN
1360 &pLastLoggedInPort); // must return non-NULL; when a port_id
1361 // is not found, this pointer marks the
1362 // end of the singly linked list
1363
1364 if( pLoggedInPort == NULL) // WWN not found -New Port
1365 {
1366 pLoggedInPort = CreateFcPort(
1367 cpqfcHBAdata,
1368 pLastLoggedInPort,
1369 fchs,
1370 &logi);
1371 if( pLoggedInPort == NULL )
1372 {
1373 printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1374 // Now Q a LOGOut Request, since we won't be talking to that device
1375
1376 NeedReject = TRUE;
1377
1378 // set reject reason code
1379 ls_reject_code =
1380 LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES);
1381
1382 }
1383 }
1384 if( !NeedReject )
1385 {
1386
1387 // OK - we have valid fcPort ptr; set fields accordingly.
1388 // (not PDISC, not Originator)
1389 SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1390
1391 // send 'ACC' reply
1392 cpqfcTSPutLinkQue( cpqfcHBAdata,
1393 ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1394 fchs );
1395 }
1396 }
1397 else // Payload unacceptable
1398 {
1399 printk("payload unacceptable\n");
1400 NeedReject = TRUE; // reject code already set
1401 }
1402
1403 if( NeedReject)
1404 {
1405 // The PDISC failed. Set login struct flags accordingly,
1406 // terminate any I/O to this port, and Q a PLOGI
1407 pLoggedInPort->pdisc = FALSE;
1408 pLoggedInPort->prli = FALSE;
1409 pLoggedInPort->plogi = FALSE;
1410
1411 fchs->reserved = ls_reject_code; // borrow this (unused) field
1412
1413 // send 'RJT' reply
1414 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
1415 }
1416
1417 // terminate any exchanges with this device...
1418 if( pLoggedInPort )
1419 {
1420 cpqfcTSTerminateExchange( cpqfcHBAdata,
1421 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1422 }
1423 break;
1424
1425
1426
1427 case 0x1020: // PRLI?
1428 {
1429 BOOLEAN NeedReject = TRUE;
1430 pLoggedInPort = fcFindLoggedInPort(
1431 fcChip,
1432 NULL, // don't search Scsi Nexus
1433 (fchs->s_id & 0xFFFFFF), // search linked list for port_id
1434 NULL, // DON'T search linked list for WWN
1435 NULL); // don't care
1436
1437 if( pLoggedInPort == NULL )
1438 {
1439 // huh?
1440 printk(" Unexpected PRLI Request -not logged in!\n");
1441
1442 // set reject reason code
1443 ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1444
1445 // Q a LOGOut here?
1446 }
1447 else
1448 {
1449 // verify the PRLI ACC payload
1450 if( !verify_PRLI( fchs, &ls_reject_code) )
1451 {
1452 // PRLI Reply is acceptable; were we expecting it?
1453 if( pLoggedInPort->plogi )
1454 {
1455 // yes, we expected the PRLI ACC (not PDISC; not Originator)
1456 SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1457
1458 // Q an ACCept Reply
1459 cpqfcTSPutLinkQue( cpqfcHBAdata,
1460 ELS_PRLI_ACC,
1461 fchs );
1462
1463 NeedReject = FALSE;
1464 }
1465 else
1466 {
1467 // huh?
1468 printk(" (unexpected) PRLI REQEST with plogi FALSE\n");
1469
1470 // set reject reason code
1471 ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1472
1473 // Q a LOGOut here?
1474
1475 }
1476 }
1477 else
1478 {
1479 printk(" PRLI REQUEST payload failed verify\n");
1480 // (reject code set by "verify")
1481
1482 // Q a LOGOut here?
1483 }
1484 }
1485
1486 if( NeedReject )
1487 {
1488 // Q a ReJecT Reply with reason code
1489 fchs->reserved = ls_reject_code;
1490 cpqfcTSPutLinkQue( cpqfcHBAdata,
1491 ELS_RJT, // Q Type
1492 fchs );
1493 }
1494 }
1495 break;
1496
1497
1498
1499
1500 case 0x0005: // LOGOut?
1501 {
1502 // was this LOGOUT because we sent a ELS_PDISC to an FC device
1503 // with changed (or new) port_id, or does the port refuse
1504 // to communicate to us?
1505 // We maintain a logout counter - if we get 3 consecutive LOGOuts,
1506 // give up!
1507 LOGOUT_PAYLOAD logo;
1508 BOOLEAN GiveUpOnDevice = FALSE;
1509 ULONG ls_reject_code = 0;
1510
1511 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo));
1512
1513 pLoggedInPort = fcFindLoggedInPort(
1514 fcChip,
1515 NULL, // don't search Scsi Nexus
1516 0, // don't search linked list for port_id
1517 &logo.port_name[0], // search linked list for WWN
1518 NULL); // don't care about end of list
1519
1520 if( pLoggedInPort ) // found the device?
1521 {
1522 // Q an ACC reply
1523 cpqfcTSPutLinkQue( cpqfcHBAdata,
1524 ELS_LOGO_ACC, // Q Type
1525 fchs ); // device to respond to
1526
1527 // set login struct fields (LOGO_counter increment)
1528 SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1529
1530 // are we an Initiator?
1531 if( fcChip->Options.initiator)
1532 {
1533 // we're an Initiator, so check if we should
1534 // try (another?) login
1535
1536 // Fabrics routinely log out from us after
1537 // getting device info - don't try to log them
1538 // back in.
1539 if( (fchs->s_id & 0xFFF000) == 0xFFF000 )
1540 {
1541 ; // do nothing
1542 }
1543 else if( pLoggedInPort->LOGO_counter <= 3)
1544 {
1545 // try (another) login (PLOGI request)
1546
1547 cpqfcTSPutLinkQue( cpqfcHBAdata,
1548 ELS_PLOGI, // Q Type
1549 fchs );
1550
1551 // Terminate I/O with "retry" potential
1552 cpqfcTSTerminateExchange( cpqfcHBAdata,
1553 &pLoggedInPort->ScsiNexus,
1554 PORTID_CHANGED);
1555 }
1556 else
1557 {
1558 printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",
1559 fchs->s_id &&0xFFFFFF);
1560 GiveUpOnDevice = TRUE;
1561 }
1562 }
1563 else
1564 {
1565 GiveUpOnDevice = TRUE;
1566 }
1567
1568
1569 if( GiveUpOnDevice == TRUE )
1570 {
1571 cpqfcTSTerminateExchange( cpqfcHBAdata,
1572 &pLoggedInPort->ScsiNexus,
1573 DEVICE_REMOVED);
1574 }
1575 }
1576 else // we don't know this WWN!
1577 {
1578 // Q a ReJecT Reply with reason code
1579 fchs->reserved = ls_reject_code;
1580 cpqfcTSPutLinkQue( cpqfcHBAdata,
1581 ELS_RJT, // Q Type
1582 fchs );
1583 }
1584 }
1585 break;
1586
1587
1588
1589
1590 // FABRIC only case
1591 case 0x0461: // ELS RSCN (Registered State Change Notification)?
1592 {
1593 int Ports;
1594 int i;
1595 __u32 Buff;
1596 // Typically, one or more devices have been added to or dropped
1597 // from the Fabric.
1598 // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
1599 // The first 32-bit word has a 2-byte Payload Length, which
1600 // includes the 4 bytes of the first word. Consequently,
1601 // this PL len must never be less than 4, must be a multiple of 4,
1602 // and has a specified max value 256.
1603 // (Endianess!)
1604 Ports = ((fchs->pl[0] >>24) - 4) / 4;
1605 Ports = Ports > 63 ? 63 : Ports;
1606
1607 printk(" RSCN ports: %d\n", Ports);
1608 if( Ports <= 0 ) // huh?
1609 {
1610 // ReJecT the command
1611 fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0);
1612
1613 cpqfcTSPutLinkQue( cpqfcHBAdata,
1614 ELS_RJT, // Q Type
1615 fchs );
1616
1617 break;
1618 }
1619 else // Accept the command
1620 {
1621 cpqfcTSPutLinkQue( cpqfcHBAdata,
1622 ELS_ACC, // Q Type
1623 fchs );
1624 }
1625
1626 // Check the "address format" to determine action.
1627 // We have 3 cases:
1628 // 0 = Port Address; 24-bit address of affected device
1629 // 1 = Area Address; MS 16 bits valid
1630 // 2 = Domain Address; MS 8 bits valid
1631 for( i=0; i<Ports; i++)
1632 {
1633 BigEndianSwap( (UCHAR*)&fchs->pl[i+1],(UCHAR*)&Buff, 4);
1634 switch( Buff & 0xFF000000)
1635 {
1636
1637 case 0: // Port Address?
1638
1639 case 0x01000000: // Area Domain?
1640 case 0x02000000: // Domain Address
1641 // For example, "port_id" 0x201300
1642 // OK, let's try a Name Service Request (Query)
1643 fchs->s_id = 0xFFFFFC; // Name Server Address
1644 cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
1645
1646 break;
1647
1648
1649 default: // huh? new value on version change?
1650 break;
1651 }
1652 }
1653 }
1654 break;
1655
1656
1657
1658
1659 default: // don't support this request (yet)
1660 // set reject reason code
1661 fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM,
1662 REQUEST_NOT_SUPPORTED);
1663
1664 cpqfcTSPutLinkQue( cpqfcHBAdata,
1665 ELS_RJT, // Q Type
1666 fchs );
1667 break;
1668 }
1669}
1670
1671
1672static void ProcessELS_Reply(
1673 CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
1674{
1675 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1676 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1677 ULONG ox_id = (fchs->ox_rx_id >>16);
1678 ULONG ls_reject_code;
1679 PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
1680
1681 // If this is a valid reply, then we MUST have sent a request.
1682 // Verify that we can find a valid request OX_ID corresponding to
1683 // this reply
1684
1685
1686 if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
1687 {
1688 printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ",
1689 ox_id, fchs->ox_rx_id & 0xffff);
1690 goto Quit; // exit this routine
1691 }
1692
1693
1694 // Is the reply a RJT (reject)?
1695 if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
1696 {
1697// ****** REJECT REPLY ********
1698 switch( Exchanges->fcExchange[ox_id].type )
1699 {
1700
1701 case ELS_FDISC: // we sent out Fabric Discovery
1702 case ELS_FLOGI: // we sent out FLOGI
1703
1704 printk("RJT received on Fabric Login from %Xh, reason %Xh\n",
1705 fchs->s_id, fchs->pl[1]);
1706
1707 break;
1708
1709 default:
1710 break;
1711 }
1712
1713 goto Done;
1714 }
1715
1716 // OK, we have an ACCept...
1717 // What's the ACC type? (according to what we sent)
1718 switch( Exchanges->fcExchange[ox_id].type )
1719 {
1720
1721 case ELS_PLOGI: // we sent out PLOGI
1722 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
1723 {
1724 LOGIN_PAYLOAD logi; // FC-PH Port Login
1725
1726 // login ACC payload acceptable; search for WWN in our list
1727 // of fcPorts
1728
1729 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1730
1731 pLoggedInPort = fcFindLoggedInPort(
1732 fcChip,
1733 NULL, // don't search Scsi Nexus
1734 0, // don't search linked list for port_id
1735 &logi.port_name[0], // search linked list for WWN
1736 &pLastLoggedInPort); // must return non-NULL; when a port_id
1737 // is not found, this pointer marks the
1738 // end of the singly linked list
1739
1740 if( pLoggedInPort == NULL) // WWN not found - new port
1741 {
1742
1743 pLoggedInPort = CreateFcPort(
1744 cpqfcHBAdata,
1745 pLastLoggedInPort,
1746 fchs,
1747 &logi);
1748
1749 if( pLoggedInPort == NULL )
1750 {
1751 printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1752 // Now Q a LOGOut Request, since we won't be talking to that device
1753
1754 goto Done; // exit with error! dropped login frame
1755 }
1756 }
1757 else // WWN was already known. Ensure that any open
1758 // exchanges for this WWN are terminated.
1759 // NOTE: It's possible that a device can change its
1760 // 24-bit port_id after a Link init or Fabric change
1761 // (e.g. LIP or Fabric RSCN). In that case, the old
1762 // 24-bit port_id may be duplicated, or no longer exist.
1763 {
1764
1765 cpqfcTSTerminateExchange( cpqfcHBAdata,
1766 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1767 }
1768
1769 // We have an fcPort struct - set fields accordingly
1770 // not PDISC, originator
1771 SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
1772
1773 // We just set a "port_id"; is it duplicated?
1774 TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
1775
1776 // For Fabric operation, we issued PLOGI to 0xFFFFFC
1777 // so we can send SCR (State Change Registration)
1778 // Check for this special case...
1779 if( fchs->s_id == 0xFFFFFC )
1780 {
1781 // PLOGI ACC was a Fabric response... issue SCR
1782 fchs->s_id = 0xFFFFFD; // address for SCR
1783 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs);
1784 }
1785
1786 else
1787 {
1788 // Now we need a PRLI to enable FCP-SCSI operation
1789 // set flags and Q up a ELS_PRLI
1790 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs);
1791 }
1792 }
1793 else
1794 {
1795 // login payload unacceptable - reason in ls_reject_code
1796 // Q up a Logout Request
1797 printk("Login Payload unacceptable\n");
1798
1799 }
1800 break;
1801
1802
1803 // PDISC logic very similar to PLOGI, except we never want
1804 // to allocate mem for "new" port, and we set flags differently
1805 // (might combine later with PLOGI logic for efficiency)
1806 case ELS_PDISC: // we sent out PDISC
1807 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
1808 {
1809 LOGIN_PAYLOAD logi; // FC-PH Port Login
1810 BOOLEAN NeedLogin = FALSE;
1811
1812 // login payload acceptable; search for WWN in our list
1813 // of (previously seen) fcPorts
1814
1815 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1816
1817 pLoggedInPort = fcFindLoggedInPort(
1818 fcChip,
1819 NULL, // don't search Scsi Nexus
1820 0, // don't search linked list for port_id
1821 &logi.port_name[0], // search linked list for WWN
1822 &pLastLoggedInPort); // must return non-NULL; when a port_id
1823 // is not found, this pointer marks the
1824 // end of the singly linked list
1825
1826 if( pLoggedInPort != NULL) // WWN found?
1827 {
1828 // WWN has same port_id as last login? (Of course, a properly
1829 // working FC device should NEVER ACCept a PDISC if it's
1830 // port_id changed, but check just in case...)
1831 if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
1832 {
1833 // Yes. We were expecting PDISC?
1834 if( pLoggedInPort->pdisc )
1835 {
1836 int i;
1837
1838
1839 // PDISC expected -- set fields. (PDISC, Originator)
1840 SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE);
1841
1842 // We are ready to resume FCP-SCSI to this device...
1843 // Do we need to start anything that was Queued?
1844
1845 for( i=0; i< TACH_SEST_LEN; i++)
1846 {
1847 // see if any exchange for this PDISC'd port was queued
1848 if( ((fchs->s_id &0xFFFFFF) ==
1849 (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
1850 &&
1851 (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED))
1852 {
1853 fchs->reserved = i; // copy ExchangeID
1854// printk(" *Q x_ID %Xh after PDISC* ",i);
1855
1856 cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs );
1857 }
1858 }
1859
1860 // Complete commands Q'd while we were waiting for Login
1861
1862 UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
1863 }
1864 else
1865 {
1866 printk("Not expecting PDISC (pdisc=FALSE)\n");
1867 NeedLogin = TRUE;
1868 }
1869 }
1870 else
1871 {
1872 printk("PDISC PortID change: old %Xh, new %Xh\n",
1873 pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
1874 NeedLogin = TRUE;
1875
1876 }
1877 }
1878 else
1879 {
1880 printk("PDISC ACC from unknown WWN\n");
1881 NeedLogin = TRUE;
1882 }
1883
1884 if( NeedLogin)
1885 {
1886
1887 // The PDISC failed. Set login struct flags accordingly,
1888 // terminate any I/O to this port, and Q a PLOGI
1889 if( pLoggedInPort ) // FC device previously known?
1890 {
1891
1892 cpqfcTSPutLinkQue( cpqfcHBAdata,
1893 ELS_LOGO, // Q Type
1894 fchs ); // has port_id to send to
1895
1896 // There are a variety of error scenarios which can result
1897 // in PDISC failure, so as a catchall, add the check for
1898 // duplicate port_id.
1899 TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
1900
1901// TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
1902 pLoggedInPort->pdisc = FALSE;
1903 pLoggedInPort->prli = FALSE;
1904 pLoggedInPort->plogi = FALSE;
1905
1906 cpqfcTSTerminateExchange( cpqfcHBAdata,
1907 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1908 }
1909 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs );
1910 }
1911 }
1912 else
1913 {
1914 // login payload unacceptable - reason in ls_reject_code
1915 // Q up a Logout Request
1916 printk("ERROR: Login Payload unacceptable!\n");
1917
1918 }
1919
1920 break;
1921
1922
1923
1924 case ELS_PRLI: // we sent out PRLI
1925
1926
1927 pLoggedInPort = fcFindLoggedInPort(
1928 fcChip,
1929 NULL, // don't search Scsi Nexus
1930 (fchs->s_id & 0xFFFFFF), // search linked list for port_id
1931 NULL, // DON'T search linked list for WWN
1932 NULL); // don't care
1933
1934 if( pLoggedInPort == NULL )
1935 {
1936 // huh?
1937 printk(" Unexpected PRLI ACCept frame!\n");
1938
1939 // Q a LOGOut here?
1940
1941 goto Done;
1942 }
1943
1944 // verify the PRLI ACC payload
1945 if( !verify_PRLI( fchs, &ls_reject_code) )
1946 {
1947 // PRLI Reply is acceptable; were we expecting it?
1948 if( pLoggedInPort->plogi )
1949 {
1950 // yes, we expected the PRLI ACC (not PDISC; Originator)
1951 SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
1952
1953 // OK, let's send a REPORT_LUNS command to determine
1954 // whether VSA or PDA FCP-LUN addressing is used.
1955
1956 cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
1957
1958 // It's possible that a device we were talking to changed
1959 // port_id, and has logged back in. This function ensures
1960 // that I/O will resume.
1961 UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
1962
1963 }
1964 else
1965 {
1966 // huh?
1967 printk(" (unexpected) PRLI ACCept with plogi FALSE\n");
1968
1969 // Q a LOGOut here?
1970 goto Done;
1971 }
1972 }
1973 else
1974 {
1975 printk(" PRLI ACCept payload failed verify\n");
1976
1977 // Q a LOGOut here?
1978 }
1979
1980 break;
1981
1982 case ELS_FLOGI: // we sent out FLOGI (Fabric Login)
1983
1984 // update the upper 16 bits of our port_id in Tachyon
1985 // the switch adds those upper 16 bits when responding
1986 // to us (i.e. we are the destination_id)
1987 fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
1988 writel( fcChip->Registers.my_al_pa,
1989 fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
1990
1991 // now send out a PLOGI to the well known port_id 0xFFFFFC
1992 fchs->s_id = 0xFFFFFC;
1993 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs);
1994
1995 break;
1996
1997
1998 case ELS_FDISC: // we sent out FDISC (Fabric Discovery (Login))
1999
2000 printk( " ELS_FDISC success ");
2001 break;
2002
2003
2004 case ELS_SCR: // we sent out State Change Registration
2005 // now we can issue Name Service Request to find any
2006 // Fabric-connected devices we might want to login to.
2007
2008
2009 fchs->s_id = 0xFFFFFC; // Name Server Address
2010 cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
2011
2012
2013 break;
2014
2015
2016 default:
2017 printk(" *Discarding unknown ACC frame, xID %04X/%04X* ",
2018 ox_id, fchs->ox_rx_id & 0xffff);
2019 break;
2020 }
2021
2022
2023Done:
2024 // Regardless of whether the Reply is valid or not, the
2025 // the exchange is done - complete
2026 cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16));
2027
2028Quit:
2029 return;
2030}
2031
2032
2033
2034
2035
2036
2037// **************** Fibre Channel Services **************
2038// This is where we process the Directory (Name) Service Reply
2039// to know which devices are on the Fabric
2040
2041static void ProcessFCS_Reply(
2042 CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
2043{
2044 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2045 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2046 ULONG ox_id = (fchs->ox_rx_id >>16);
2047// ULONG ls_reject_code;
2048// PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
2049
2050 // If this is a valid reply, then we MUST have sent a request.
2051 // Verify that we can find a valid request OX_ID corresponding to
2052 // this reply
2053
2054 if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
2055 {
2056 printk(" *Discarding Reply frame, xID %04X/%04X* ",
2057 ox_id, fchs->ox_rx_id & 0xffff);
2058 goto Quit; // exit this routine
2059 }
2060
2061
2062 // OK, we were expecting it. Now check to see if it's a
2063 // "Name Service" Reply, and if so force a re-validation of
2064 // Fabric device logins (i.e. Start the login timeout and
2065 // send PDISC or PLOGI)
2066 // (Endianess Byte Swap?)
2067 if( fchs->pl[1] == 0x02FC ) // Name Service
2068 {
2069 // got a new (or NULL) list of Fabric attach devices...
2070 // Invalidate current logins
2071
2072 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
2073 while( pLoggedInPort ) // for all ports which are expecting
2074 // PDISC after the next LIP, set the
2075 // logoutTimer
2076 {
2077
2078 if( (pLoggedInPort->port_id & 0xFFFF00) // Fabric device?
2079 &&
2080 (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port
2081 {
2082 pLoggedInPort->LOGO_timer = 6; // what's the Fabric timeout??
2083 // suspend any I/O in progress until
2084 // PDISC received...
2085 pLoggedInPort->prli = FALSE; // block FCP-SCSI commands
2086 }
2087
2088 pLoggedInPort = pLoggedInPort->pNextPort;
2089 }
2090
2091 if( fchs->pl[2] == 0x0280) // ACCept?
2092 {
2093 // Send PLOGI or PDISC to these Fabric devices
2094 SendLogins( cpqfcHBAdata, &fchs->pl[4] );
2095 }
2096
2097
2098 // As of this writing, the only reason to reject is because NO
2099 // devices are left on the Fabric. We already started
2100 // "logged out" timers; if the device(s) don't come
2101 // back, we'll do the implicit logout in the heart beat
2102 // timer routine
2103 else // ReJecT
2104 {
2105 // this just means no Fabric device is visible at this instant
2106 }
2107 }
2108
2109 // Regardless of whether the Reply is valid or not, the
2110 // the exchange is done - complete
2111 cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16));
2112
2113Quit:
2114 return;
2115}
2116
2117
2118
2119
2120
2121
2122
2123static void AnalyzeIncomingFrame(
2124 CPQFCHBA *cpqfcHBAdata,
2125 ULONG QNdx )
2126{
2127 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2128 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2129 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
2130 TachFCHDR_GCMND* fchs =
2131 (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff;
2132// ULONG ls_reject_code; // reason for rejecting login
2133 LONG ExchangeID;
2134// FC_LOGGEDIN_PORT *pLoggedInPort;
2135 BOOLEAN AbortAccept;
2136
2137 ENTER("AnalyzeIncomingFrame");
2138
2139
2140
2141 switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown
2142 {
2143
2144 case SFQ_UNKNOWN: // unknown frame (e.g. LIP position frame, NOP, etc.)
2145
2146
2147 // ********* FC-4 Device Data/ Fibre Channel Service *************
2148 if( ((fchs->d_id &0xF0000000) == 0) // R_CTL (upper nibble) 0x0?
2149 &&
2150 (fchs->f_ctl & 0x20000000) ) // TYPE 20h is Fibre Channel Service
2151 {
2152
2153 // ************** FCS Reply **********************
2154
2155 if( (fchs->d_id & 0xff000000L) == 0x03000000L) // (31:23 R_CTL)
2156 {
2157 ProcessFCS_Reply( cpqfcHBAdata, fchs );
2158
2159 } // end of FCS logic
2160
2161 }
2162
2163
2164 // *********** Extended Link Service **************
2165
2166 else if( fchs->d_id & 0x20000000 // R_CTL 0x2?
2167 &&
2168 (fchs->f_ctl & 0x01000000) ) // TYPE = 1
2169 {
2170
2171 // these frames are either a response to
2172 // something we sent (0x23) or "unsolicited"
2173 // frames (0x22).
2174
2175
2176 // **************Extended Link REPLY **********************
2177 // R_CTL Solicited Control Reply
2178
2179 if( (fchs->d_id & 0xff000000L) == 0x23000000L) // (31:23 R_CTL)
2180 {
2181
2182 ProcessELS_Reply( cpqfcHBAdata, fchs );
2183
2184 } // end of "R_CTL Solicited Control Reply"
2185
2186
2187
2188
2189 // **************Extended Link REQUEST **********************
2190 // (unsolicited commands from another port or task...)
2191
2192 // R_CTL Ext Link REQUEST
2193 else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
2194 (fchs->ox_rx_id != 0xFFFFFFFFL) ) // (ignore LIP frame)
2195 {
2196
2197
2198
2199 ProcessELS_Request( cpqfcHBAdata, fchs );
2200
2201 }
2202
2203
2204
2205 // ************** LILP **********************
2206 else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
2207 (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
2208
2209 {
2210 // SANMark specifies that when available, we must use
2211 // the LILP frame to determine which ALPAs to send Port Discovery
2212 // to...
2213
2214 if( fchs->pl[0] == 0x0711L) // ELS_PLOGI?
2215 {
2216// UCHAR *ptr = (UCHAR*)&fchs->pl[1];
2217// printk(" %d ALPAs found\n", *ptr);
2218 memcpy( fcChip->LILPmap, &fchs->pl[1], 32*4); // 32 DWORDs
2219 fcChip->Options.LILPin = 1; // our LILPmap is valid!
2220 // now post to make Port Discovery happen...
2221 cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, fchs);
2222 }
2223 }
2224 }
2225
2226
2227 // ***************** BASIC LINK SERVICE *****************
2228
2229 else if( fchs->d_id & 0x80000000 // R_CTL:
2230 && // Basic Link Service Request
2231 !(fchs->f_ctl & 0xFF000000) ) // type=0 for BLS
2232 {
2233
2234 // Check for ABTS (Abort Sequence)
2235 if( (fchs->d_id & 0x8F000000) == 0x81000000)
2236 {
2237 // look for OX_ID, S_ID pair that matches in our
2238 // fcExchanges table; if found, reply with ACCept and complete
2239 // the exchange
2240
2241 // Per PLDA, an ABTS is sent by an initiator; therefore
2242 // assume that if we have an exhange open to the port who
2243 // sent ABTS, it will be the d_id of what we sent.
2244 for( ExchangeID = 0, AbortAccept=FALSE;
2245 ExchangeID < TACH_SEST_LEN; ExchangeID++)
2246 {
2247 // Valid "target" exchange 24-bit port_id matches?
2248 // NOTE: For the case of handling Intiator AND Target
2249 // functions on the same chip, we can have TWO Exchanges
2250 // with the same OX_ID -- OX_ID/FFFF for the CMND, and
2251 // OX_ID/RX_ID for the XRDY or DATA frame(s). Ideally,
2252 // we would like to support ABTS from Initiators or Targets,
2253 // but it's not clear that can be supported on Tachyon for
2254 // all cases (requires more investigation).
2255
2256 if( (Exchanges->fcExchange[ ExchangeID].type == SCSI_TWE ||
2257 Exchanges->fcExchange[ ExchangeID].type == SCSI_TRE)
2258 &&
2259 ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2260 (fchs->s_id & 0xFFFFFF)) )
2261 {
2262
2263 // target xchnge port_id matches -- how about OX_ID?
2264 if( (Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id &0xFFFF0000)
2265 == (fchs->ox_rx_id & 0xFFFF0000) )
2266 // yes! post ACCept response; will be completed by fcStart
2267 {
2268 Exchanges->fcExchange[ ExchangeID].status = TARGET_ABORT;
2269
2270 // copy (add) rx_id field for simplified ACCept reply
2271 fchs->ox_rx_id =
2272 Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id;
2273
2274 cpqfcTSPutLinkQue( cpqfcHBAdata,
2275 BLS_ABTS_ACC, // Q Type
2276 fchs ); // void QueContent
2277 AbortAccept = TRUE;
2278 printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n",
2279 fchs->ox_rx_id, Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id);
2280 break; // ABTS can affect only ONE exchange -exit loop
2281 }
2282 }
2283 } // end of FOR loop
2284 if( !AbortAccept ) // can't ACCept ABTS - send Reject
2285 {
2286 printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n",
2287 fchs->ox_rx_id);
2288 if( Exchanges->fcExchange[ ExchangeID].type
2289 &&
2290 !(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len
2291 & 0x80000000))
2292 {
2293 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
2294 }
2295 else
2296 {
2297 printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n",
2298 ExchangeID, fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len);
2299 }
2300 }
2301 }
2302
2303 // Check for BLS {ABTS? (Abort Sequence)} ACCept
2304 else if( (fchs->d_id & 0x8F000000) == 0x84000000)
2305 {
2306 // target has responded with ACC for our ABTS;
2307 // complete the indicated exchange with ABORTED status
2308 // Make no checks for correct RX_ID, since
2309 // all we need to conform ABTS ACC is the OX_ID.
2310 // Verify that the d_id matches!
2311
2312 ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
2313// printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n",
2314// fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff,
2315// Exchanges->fcExchange[ExchangeID].status);
2316
2317
2318
2319 if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
2320 {
2321 // Does "target" exchange 24-bit port_id match?
2322 // (See "NOTE" above for handling Intiator AND Target in
2323 // the same device driver)
2324 // First, if this is a target response, then we originated
2325 // (initiated) it with BLS_ABTS:
2326
2327 if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
2328
2329 &&
2330 // Second, does the source of this ACC match the destination
2331 // of who we originally sent it to?
2332 ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2333 (fchs->s_id & 0xFFFFFF)) )
2334 {
2335 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
2336 }
2337 }
2338 }
2339 // Check for BLS {ABTS? (Abort Sequence)} ReJecT
2340 else if( (fchs->d_id & 0x8F000000) == 0x85000000)
2341 {
2342 // target has responded with RJT for our ABTS;
2343 // complete the indicated exchange with ABORTED status
2344 // Make no checks for correct RX_ID, since
2345 // all we need to conform ABTS ACC is the OX_ID.
2346 // Verify that the d_id matches!
2347
2348 ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
2349// printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n",
2350// fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
2351
2352 if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
2353 {
2354 // Does "target" exchange 24-bit port_id match?
2355 // (See "NOTE" above for handling Intiator AND Target in
2356 // the same device driver)
2357 // First, if this is a target response, then we originated
2358 // (initiated) it with BLS_ABTS:
2359
2360 if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
2361
2362 &&
2363 // Second, does the source of this ACC match the destination
2364 // of who we originally sent it to?
2365 ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2366 (fchs->s_id & 0xFFFFFF)) )
2367 {
2368 // YES! NOTE: There is a bug in CPQ's RA-4000 box
2369 // where the "reason code" isn't returned in the payload
2370 // For now, simply presume the reject is because the target
2371 // already completed the exchange...
2372
2373// printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
2374 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
2375 }
2376 }
2377 } // end of ABTS check
2378 } // end of Basic Link Service Request
2379 break;
2380
2381 default:
2382 printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n",
2383 fcLQ->Qitem[QNdx].Type,
2384 fcLQ->Qitem[QNdx].Type);
2385 break;
2386 }
2387}
2388
2389
2390// Function for Port Discovery necessary after every FC
2391// initialization (e.g. LIP).
2392// Also may be called if from Fabric Name Service logic.
2393
2394static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds )
2395{
2396 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2397 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2398 ULONG ulStatus=0;
2399 TachFCHDR_GCMND fchs; // copy fields for transmission
2400 int i;
2401 ULONG loginType;
2402 LONG ExchangeID;
2403 PFC_LOGGEDIN_PORT pLoggedInPort;
2404 __u32 PortIds[ number_of_al_pa];
2405 int NumberOfPorts=0;
2406
2407 // We're going to presume (for now) that our limit of Fabric devices
2408 // is the same as the number of alpa on a private loop (126 devices).
2409 // (Of course this could be changed to support however many we have
2410 // memory for).
2411 memset( &PortIds[0], 0, sizeof(PortIds));
2412
2413 // First, check if this login is for our own Link Initialization
2414 // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
2415 // from a switch. If we are logging into Fabric devices, we'll
2416 // have a non-NULL FabricPortId pointer
2417
2418 if( FabricPortIds != NULL) // may need logins
2419 {
2420 int LastPort=FALSE;
2421 i = 0;
2422 while( !LastPort)
2423 {
2424 // port IDs From NSR payload; byte swap needed?
2425 BigEndianSwap( (UCHAR*)FabricPortIds, (UCHAR*)&PortIds[i], 4);
2426
2427// printk("FPortId[%d] %Xh ", i, PortIds[i]);
2428 if( PortIds[i] & 0x80000000)
2429 LastPort = TRUE;
2430
2431 PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
2432 // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
2433 // erroneously use ALPA 0.
2434 if( PortIds[i] ) // need non-zero port_id...
2435 i++;
2436
2437 if( i >= number_of_al_pa ) // (in)sanity check
2438 break;
2439 FabricPortIds++; // next...
2440 }
2441
2442 NumberOfPorts = i;
2443// printk("NumberOf Fabric ports %d", NumberOfPorts);
2444 }
2445
2446 else // need to send logins on our "local" link
2447 {
2448
2449 // are we a loop port? If so, check for reception of LILP frame,
2450 // and if received use it (SANMark requirement)
2451 if( fcChip->Options.LILPin )
2452 {
2453 int j=0;
2454 // sanity check on number of ALPAs from LILP frame...
2455 // For format of LILP frame, see FC-AL specs or
2456 // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
2457 // First byte is number of ALPAs
2458 i = fcChip->LILPmap[0] >= (32*4) ? 32*4 : fcChip->LILPmap[0];
2459 NumberOfPorts = i;
2460// printk(" LILP alpa count %d ", i);
2461 while( i > 0)
2462 {
2463 PortIds[j] = fcChip->LILPmap[1+ j];
2464 j++; i--;
2465 }
2466 }
2467 else // have to send login to everybody
2468 {
2469 int j=0;
2470 i = number_of_al_pa;
2471 NumberOfPorts = i;
2472 while( i > 0)
2473 {
2474 PortIds[j] = valid_al_pa[j]; // all legal ALPAs
2475 j++; i--;
2476 }
2477 }
2478 }
2479
2480
2481 // Now we have a copy of the port_ids (and how many)...
2482 for( i = 0; i < NumberOfPorts; i++)
2483 {
2484 // 24-bit FC Port ID
2485 fchs.s_id = PortIds[i]; // note: only 8-bits used for ALPA
2486
2487
2488 // don't log into ourselves (Linux Scsi disk scan will stop on
2489 // no TARGET support error on us, and quit trying for rest of devices)
2490 if( (fchs.s_id & 0xFF ) == (fcChip->Registers.my_al_pa & 0xFF) )
2491 continue;
2492
2493 // fabric login needed?
2494 if( (fchs.s_id == 0) ||
2495 (fcChip->Options.fabric == 1) )
2496 {
2497 fcChip->Options.flogi = 1; // fabric needs longer for login
2498 // Do we need FLOGI or FDISC?
2499 pLoggedInPort = fcFindLoggedInPort(
2500 fcChip,
2501 NULL, // don't search SCSI Nexus
2502 0xFFFFFC, // search linked list for Fabric port_id
2503 NULL, // don't search WWN
2504 NULL); // (don't care about end of list)
2505
2506 if( pLoggedInPort ) // If found, we have prior experience with
2507 // this port -- check whether PDISC is needed
2508 {
2509 if( pLoggedInPort->flogi )
2510 {
2511 // does the switch support FDISC?? (FLOGI for now...)
2512 loginType = ELS_FLOGI; // prior FLOGI still valid
2513 }
2514 else
2515 loginType = ELS_FLOGI; // expired FLOGI
2516 }
2517 else // first FLOGI?
2518 loginType = ELS_FLOGI;
2519
2520
2521 fchs.s_id = 0xFFFFFE; // well known F_Port address
2522
2523 // Fabrics are not required to support FDISC, and
2524 // it's not clear if that helps us anyway, since
2525 // we'll want a Name Service Request to re-verify
2526 // visible devices...
2527 // Consequently, we always want our upper 16 bit
2528 // port_id to be zero (we'll be rejected if we
2529 // use our prior port_id if we've been plugged into
2530 // a different switch port).
2531 // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
2532 // If our ALPA is 55h for instance, we want the FC frame
2533 // s_id to be 0x000055, while Tach's my_al_pa register
2534 // must be 0x000155, to force an OPN at ALPA 0
2535 // (the Fabric port)
2536 fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
2537 writel( fcChip->Registers.my_al_pa | 0x0100,
2538 fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
2539 }
2540
2541 else // not FLOGI...
2542 {
2543 // should we send PLOGI or PDISC? Check if any prior port_id
2544 // (e.g. alpa) completed a PLOGI/PRLI exchange by checking
2545 // the pdisc flag.
2546
2547 pLoggedInPort = fcFindLoggedInPort(
2548 fcChip,
2549 NULL, // don't search SCSI Nexus
2550 fchs.s_id, // search linked list for al_pa
2551 NULL, // don't search WWN
2552 NULL); // (don't care about end of list)
2553
2554
2555
2556 if( pLoggedInPort ) // If found, we have prior experience with
2557 // this port -- check whether PDISC is needed
2558 {
2559 if( pLoggedInPort->pdisc )
2560 {
2561 loginType = ELS_PDISC; // prior PLOGI and PRLI maybe still valid
2562
2563 }
2564 else
2565 loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
2566 }
2567 else // never talked to this port_id before
2568 loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
2569 }
2570
2571
2572
2573 ulStatus = cpqfcTSBuildExchange(
2574 cpqfcHBAdata,
2575 loginType, // e.g. PLOGI
2576 &fchs, // no incoming frame (we are originator)
2577 NULL, // no data (no scatter/gather list)
2578 &ExchangeID );// fcController->fcExchanges index, -1 if failed
2579
2580 if( !ulStatus ) // Exchange setup OK?
2581 {
2582 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
2583 if( !ulStatus )
2584 {
2585 // submitted to Tach's Outbound Que (ERQ PI incremented)
2586 // waited for completion for ELS type (Login frames issued
2587 // synchronously)
2588
2589 if( loginType == ELS_PDISC )
2590 {
2591 // now, we really shouldn't Revalidate SEST exchanges until
2592 // we get an ACC reply from our target and verify that
2593 // the target address/WWN is unchanged. However, when a fast
2594 // target gets the PDISC, they can send SEST Exchange data
2595 // before we even get around to processing the PDISC ACC.
2596 // Consequently, we lose the I/O.
2597 // To avoid this, go ahead and Revalidate when the PDISC goes
2598 // out, anticipating that the ACC will be truly acceptable
2599 // (this happens 99.9999....% of the time).
2600 // If we revalidate a SEST write, and write data goes to a
2601 // target that is NOT the one we originated the WRITE to,
2602 // that target is required (FCP-SCSI specs, etc) to discard
2603 // our WRITE data.
2604
2605 // Re-validate SEST entries (Tachyon hardware assists)
2606 RevalidateSEST( cpqfcHBAdata->HostAdapter, pLoggedInPort);
2607 //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
2608 }
2609 }
2610 else // give up immediately on error
2611 {
2612#ifdef LOGIN_DBG
2613 printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus );
2614#endif
2615 break;
2616 }
2617
2618
2619 if( fcChip->Registers.FMstatus.value & 0x080 ) // LDn during Port Disc.
2620 {
2621 ulStatus = LNKDWN_OSLS;
2622#ifdef LOGIN_DBG
2623 printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
2624#endif
2625 break;
2626 }
2627 // Check the exchange for bad status (i.e. FrameTimeOut),
2628 // and complete on bad status (most likely due to BAD_ALPA)
2629 // on LDn, DPC function may already complete (ABORT) a started
2630 // exchange, so check type first (type = 0 on complete).
2631 if( Exchanges->fcExchange[ExchangeID].status )
2632 {
2633#ifdef LOGIN_DBG
2634 printk("completing x_ID %X on status %Xh\n",
2635 ExchangeID, Exchanges->fcExchange[ExchangeID].status);
2636#endif
2637 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
2638 }
2639 }
2640 else // Xchange setup failed...
2641 {
2642#ifdef LOGIN_DBG
2643 printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
2644#endif
2645 break;
2646 }
2647 }
2648 if( !ulStatus )
2649 {
2650 // set the event signifying that all ALPAs were sent out.
2651#ifdef LOGIN_DBG
2652 printk("SendLogins: PortDiscDone\n");
2653#endif
2654 cpqfcHBAdata->PortDiscDone = 1;
2655
2656
2657 // TL/TS UG, pg. 184
2658 // 0x0065 = 100ms for RT_TOV
2659 // 0x01f5 = 500ms for ED_TOV
2660 fcChip->Registers.ed_tov.value = 0x006501f5L;
2661 writel( fcChip->Registers.ed_tov.value,
2662 (fcChip->Registers.ed_tov.address));
2663
2664 // set the LP_TOV back to ED_TOV (i.e. 500 ms)
2665 writel( 0x00000010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
2666 }
2667 else
2668 {
2669 printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n",
2670 ExchangeID, fchs.s_id, ulStatus);
2671 }
2672 LEAVE("SendLogins");
2673
2674}
2675
2676
2677// for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi",
2678// D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9)
2679static void ScsiReportLunsDone(Scsi_Cmnd *Cmnd)
2680{
2681 struct Scsi_Host *HostAdapter = Cmnd->device->host;
2682 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
2683 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2684 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2685 PFC_LOGGEDIN_PORT pLoggedInPort;
2686 int LunListLen=0;
2687 int i;
2688 ULONG x_ID = 0xFFFFFFFF;
2689 UCHAR *ucBuff = Cmnd->request_buffer;
2690
2691// printk("cpqfcTS: ReportLunsDone \n");
2692 // first, we need to find the Exchange for this command,
2693 // so we can find the fcPort struct to make the indicated
2694 // changes.
2695 for( i=0; i< TACH_SEST_LEN; i++)
2696 {
2697 if( Exchanges->fcExchange[i].type // exchange defined?
2698 &&
2699 (Exchanges->fcExchange[i].Cmnd == Cmnd) ) // matches?
2700
2701 {
2702 x_ID = i; // found exchange!
2703 break;
2704 }
2705 }
2706 if( x_ID == 0xFFFFFFFF)
2707 {
2708// printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
2709 goto Done; // Report Luns FC Exchange gone;
2710 // exchange probably Terminated by Implicit logout
2711 }
2712
2713
2714 // search linked list for the port_id we sent INQUIRY to
2715 pLoggedInPort = fcFindLoggedInPort( fcChip,
2716 NULL, // DON'T search Scsi Nexus (we will set it)
2717 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,
2718 NULL, // DON'T search linked list for FC WWN
2719 NULL); // DON'T care about end of list
2720
2721 if( !pLoggedInPort )
2722 {
2723// printk("cpqfcTS: ReportLuns failed - device gone\n");
2724 goto Done; // error! can't find logged in Port
2725 }
2726 LunListLen = ucBuff[3];
2727 LunListLen += ucBuff[2]>>8;
2728
2729 if( !LunListLen ) // failed
2730 {
2731 // generically speaking, a soft error means we should retry...
2732 if( (Cmnd->result >> 16) == DID_SOFT_ERROR )
2733 {
2734 if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
2735 (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
2736 {
2737 TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[ x_ID].fchs;
2738 // did we fail because of "check condition, device reset?"
2739 // e.g. the device was reset (i.e., at every power up)
2740 // retry the Report Luns
2741
2742 // who are we sending it to?
2743 // we know this because we have a copy of the command
2744 // frame from the original Report Lun command -
2745 // switch the d_id/s_id fields, because the Exchange Build
2746 // context is "reply to source".
2747
2748 fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
2749 cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
2750 }
2751 }
2752 else // probably, the device doesn't support Report Luns
2753 pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;
2754 }
2755 else // we have LUN info - check VSA mode
2756 {
2757 // for now, assume all LUNs will have same addr mode
2758 // for VSA, payload byte 8 will be 0x40; otherwise, 0
2759 pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];
2760
2761 // Since we got a Report Luns answer, set lun masking flag
2762 pLoggedInPort->ScsiNexus.LunMasking = 1;
2763
2764 if( LunListLen > 8*CPQFCTS_MAX_LUN) // We expect CPQFCTS_MAX_LUN max
2765 LunListLen = 8*CPQFCTS_MAX_LUN;
2766
2767/*
2768 printk("Device WWN %08X%08X Reports Luns @: ",
2769 (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
2770 (ULONG)(pLoggedInPort->u.liWWN>>32));
2771
2772 for( i=8; i<LunListLen+8; i+=8)
2773 {
2774 printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
2775 }
2776 printk("\n");
2777*/
2778
2779 // Since the device was kind enough to tell us where the
2780 // LUNs are, lets ensure they are contiguous for Linux's
2781 // SCSI driver scan, which expects them to start at 0.
2782 // Since Linux only supports 8 LUNs, only copy the first
2783 // eight from the report luns command
2784
2785 // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
2786 // LUNs 4001, 4004, etc., because other LUNs are masked from
2787 // this HBA (owned by someone else). We'll make those appear as
2788 // LUN 0, 1... to Linux
2789 {
2790 int j;
2791 int AppendLunList = 0;
2792 // Walk through the LUN list. The 'j' array number is
2793 // Linux's lun #, while the value of .lun[j] is the target's
2794 // lun #.
2795 // Once we build a LUN list, it's possible for a known device
2796 // to go offline while volumes (LUNs) are added. Later,
2797 // the device will do another PLOGI ... Report Luns command,
2798 // and we must not alter the existing Linux Lun map.
2799 // (This will be very rare).
2800 for( j=0; j < CPQFCTS_MAX_LUN; j++)
2801 {
2802 if( pLoggedInPort->ScsiNexus.lun[j] != 0xFF )
2803 {
2804 AppendLunList = 1;
2805 break;
2806 }
2807 }
2808 if( AppendLunList )
2809 {
2810 int k;
2811 int FreeLunIndex;
2812// printk("cpqfcTS: AppendLunList\n");
2813
2814 // If we get a new Report Luns, we cannot change
2815 // any existing LUN mapping! (Only additive entry)
2816 // For all LUNs in ReportLun list
2817 // if RL lun != ScsiNexus lun
2818 // if RL lun present in ScsiNexus lun[], continue
2819 // else find ScsiNexus lun[]==FF and add, continue
2820
2821 for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
2822 {
2823 if( pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i+1] )
2824 {
2825 // something changed from the last Report Luns
2826 printk(" cpqfcTS: Report Lun change!\n");
2827 for( k=0, FreeLunIndex=CPQFCTS_MAX_LUN;
2828 k < CPQFCTS_MAX_LUN; k++)
2829 {
2830 if( pLoggedInPort->ScsiNexus.lun[k] == 0xFF)
2831 {
2832 FreeLunIndex = k;
2833 break;
2834 }
2835 if( pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i+1] )
2836 break; // we already masked this lun
2837 }
2838 if( k >= CPQFCTS_MAX_LUN )
2839 {
2840 printk(" no room for new LUN %d\n", ucBuff[i+1]);
2841 }
2842 else if( k == FreeLunIndex ) // need to add LUN
2843 {
2844 pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i+1];
2845// printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
2846
2847 }
2848 else
2849 {
2850 // lun already known
2851 }
2852 break;
2853 }
2854 }
2855 // print out the new list...
2856 for( j=0; j< CPQFCTS_MAX_LUN; j++)
2857 {
2858 if( pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
2859 break; // done
2860// printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2861 }
2862 }
2863 else
2864 {
2865// printk("Linux SCSI LUNs[] -> Device LUNs: ");
2866 // first time - this is easy
2867 for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
2868 {
2869 pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i+1];
2870// printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2871 }
2872// printk("\n");
2873 }
2874 }
2875 }
2876
2877Done: ;
2878}
2879
2880extern int is_private_data_of_cpqfc(CPQFCHBA *hba, void * pointer);
2881extern void cpqfc_free_private_data(CPQFCHBA *hba, cpqfc_passthru_private_t *data);
2882
2883static void
2884call_scsi_done(Scsi_Cmnd *Cmnd)
2885{
2886 CPQFCHBA *hba;
2887 hba = (CPQFCHBA *) Cmnd->device->host->hostdata;
2888 // Was this command a cpqfc passthru ioctl ?
2889 if (Cmnd->sc_request != NULL && Cmnd->device->host != NULL &&
2890 Cmnd->device->host->hostdata != NULL &&
2891 is_private_data_of_cpqfc((CPQFCHBA *) Cmnd->device->host->hostdata,
2892 Cmnd->sc_request->upper_private_data)) {
2893 cpqfc_free_private_data(hba,
2894 Cmnd->sc_request->upper_private_data);
2895 Cmnd->sc_request->upper_private_data = NULL;
2896 Cmnd->result &= 0xff00ffff;
2897 Cmnd->result |= (DID_PASSTHROUGH << 16); // prevents retry
2898 }
2899 if (Cmnd->scsi_done != NULL)
2900 (*Cmnd->scsi_done)(Cmnd);
2901}
2902
2903// After successfully getting a "Process Login" (PRLI) from an
2904// FC port, we want to Discover the LUNs so that we know the
2905// addressing type (e.g., FCP-SCSI Volume Set Address, Peripheral
2906// Unit Device), and whether SSP (Selective Storage Presentation or
2907// Lun Masking) has made the LUN numbers non-zero based or
2908// non-contiguous. To remain backward compatible with the SCSI-2
2909// driver model, which expects a contiguous LUNs starting at 0,
2910// will use the ReportLuns info to map from "device" to "Linux"
2911// LUNs.
2912static void IssueReportLunsCommand(
2913 CPQFCHBA* cpqfcHBAdata,
2914 TachFCHDR_GCMND* fchs)
2915{
2916 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2917 PFC_LOGGEDIN_PORT pLoggedInPort;
2918 struct scsi_cmnd *Cmnd = NULL;
2919 struct scsi_device *ScsiDev = NULL;
2920 LONG x_ID;
2921 ULONG ulStatus;
2922 UCHAR *ucBuff;
2923
2924 if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
2925 {
2926 printk("Discard Q'd ReportLun command\n");
2927 goto Done;
2928 }
2929
2930 // find the device (from port_id) we're talking to
2931 pLoggedInPort = fcFindLoggedInPort( fcChip,
2932 NULL, // DON'T search Scsi Nexus
2933 fchs->s_id & 0xFFFFFF,
2934 NULL, // DON'T search linked list for FC WWN
2935 NULL); // DON'T care about end of list
2936 if( pLoggedInPort ) // we'd BETTER find it!
2937 {
2938
2939
2940 if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
2941 goto Done; // forget it - FC device not a "target"
2942
2943
2944 ScsiDev = scsi_get_host_dev (cpqfcHBAdata->HostAdapter);
2945 if (!ScsiDev)
2946 goto Done;
2947
2948 Cmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
2949 if (!Cmnd)
2950 goto Done;
2951
2952 ucBuff = pLoggedInPort->ReportLunsPayload;
2953
2954 memset( ucBuff, 0, REPORT_LUNS_PL);
2955
2956 Cmnd->scsi_done = ScsiReportLunsDone;
2957
2958 Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload;
2959 Cmnd->request_bufflen = REPORT_LUNS_PL;
2960
2961 Cmnd->cmnd[0] = 0xA0;
2962 Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
2963 Cmnd->cmnd[9] = (UCHAR)REPORT_LUNS_PL;
2964 Cmnd->cmd_len = 12;
2965
2966 Cmnd->device->channel = pLoggedInPort->ScsiNexus.channel;
2967 Cmnd->device->id = pLoggedInPort->ScsiNexus.target;
2968
2969
2970 ulStatus = cpqfcTSBuildExchange(
2971 cpqfcHBAdata,
2972 SCSI_IRE,
2973 fchs,
2974 Cmnd, // buffer for Report Lun data
2975 &x_ID );// fcController->fcExchanges index, -1 if failed
2976
2977 if( !ulStatus ) // Exchange setup?
2978 {
2979 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
2980 if( !ulStatus )
2981 {
2982 // submitted to Tach's Outbound Que (ERQ PI incremented)
2983 // waited for completion for ELS type (Login frames issued
2984 // synchronously)
2985 }
2986 else
2987 // check reason for Exchange not being started - we might
2988 // want to Queue and start later, or fail with error
2989 {
2990
2991 }
2992 }
2993
2994 else // Xchange setup failed...
2995 printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
2996 }
2997 else // like, we just got a PRLI ACC, and now the port is gone?
2998 {
2999 printk(" can't send ReportLuns - no login for port_id %Xh\n",
3000 fchs->s_id & 0xFFFFFF);
3001 }
3002
3003
3004
3005Done:
3006
3007 if (Cmnd)
3008 scsi_put_command (Cmnd);
3009 if (ScsiDev)
3010 scsi_free_host_dev (ScsiDev);
3011}
3012
3013
3014
3015
3016
3017
3018
3019static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata)
3020{
3021 int i;
3022 for( i = CPQFCTS_REQ_QUEUE_LEN-1; i>= 0; i--)
3023 {
3024 if( cpqfcHBAdata->BoardLockCmnd[i] != NULL )
3025 {
3026 Scsi_Cmnd *Cmnd = cpqfcHBAdata->BoardLockCmnd[i];
3027 cpqfcHBAdata->BoardLockCmnd[i] = NULL;
3028 Cmnd->result = (DID_SOFT_ERROR << 16); // ask for retry
3029// printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
3030// i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
3031 call_scsi_done(Cmnd);
3032 }
3033 }
3034}
3035
3036
3037
3038
3039
3040
3041// runs every 1 second for FC exchange timeouts and implicit FC device logouts
3042
3043void cpqfcTSheartbeat( unsigned long ptr )
3044{
3045 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)ptr;
3046 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
3047 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
3048 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
3049 ULONG i;
3050 unsigned long flags;
3051 DECLARE_MUTEX_LOCKED(BoardLock);
3052
3053 PCI_TRACE( 0xA8)
3054
3055 if( cpqfcHBAdata->BoardLock) // Worker Task Running?
3056 goto Skip;
3057
3058 // STOP _que function
3059 spin_lock_irqsave( cpqfcHBAdata->HostAdapter->host_lock, flags);
3060
3061 PCI_TRACE( 0xA8)
3062
3063
3064 cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing
3065
3066 // release the IO lock (and re-enable interrupts)
3067 spin_unlock_irqrestore( cpqfcHBAdata->HostAdapter->host_lock, flags);
3068
3069 // Ensure no contention from _quecommand or Worker process
3070 CPQ_SPINLOCK_HBA( cpqfcHBAdata)
3071
3072 PCI_TRACE( 0xA8)
3073
3074
3075 disable_irq( cpqfcHBAdata->HostAdapter->irq); // our IRQ
3076
3077 // Complete the "bad target" commands (normally only used during
3078 // initialization, since we aren't supposed to call "scsi_done"
3079 // inside the queuecommand() function). (this is overly contorted,
3080 // scsi_done can be safely called from queuecommand for
3081 // this bad target case. May want to simplify this later)
3082
3083 for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
3084 {
3085 if( cpqfcHBAdata->BadTargetCmnd[i] )
3086 {
3087 Scsi_Cmnd *Cmnd = cpqfcHBAdata->BadTargetCmnd[i];
3088 cpqfcHBAdata->BadTargetCmnd[i] = NULL;
3089 Cmnd->result = (DID_BAD_TARGET << 16);
3090 call_scsi_done(Cmnd);
3091 }
3092 else
3093 break;
3094 }
3095
3096
3097 // logged in ports -- re-login check (ports required to verify login with
3098 // PDISC after LIP within 2 secs)
3099
3100 // prevent contention
3101 while( pLoggedInPort ) // for all ports which are expecting
3102 // PDISC after the next LIP, check to see if
3103 // time is up!
3104 {
3105 // Important: we only detect "timeout" condition on TRANSITION
3106 // from non-zero to zero
3107 if( pLoggedInPort->LOGO_timer ) // time-out "armed"?
3108 {
3109 if( !(--pLoggedInPort->LOGO_timer) ) // DEC from 1 to 0?
3110 {
3111 // LOGOUT time! Per PLDA, PDISC hasn't complete in 2 secs, so
3112 // issue LOGO request and destroy all I/O with other FC port(s).
3113
3114/*
3115 printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
3116 printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n",
3117 pLoggedInPort->ScsiNexus.channel,
3118 pLoggedInPort->ScsiNexus.target,
3119 pLoggedInPort->port_id,
3120 (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
3121 (ULONG)(pLoggedInPort->u.liWWN>>32));
3122
3123*/
3124 cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
3125
3126 }
3127 // else simply decremented - maybe next time...
3128 }
3129 pLoggedInPort = pLoggedInPort->pNextPort;
3130 }
3131
3132
3133
3134
3135
3136 // ************ FC EXCHANGE TIMEOUT CHECK **************
3137
3138 for( i=0; i< TACH_MAX_XID; i++)
3139 {
3140 if( Exchanges->fcExchange[i].type ) // exchange defined?
3141 {
3142
3143 if( !Exchanges->fcExchange[i].timeOut ) // time expired
3144 {
3145 // Set Exchange timeout status
3146 Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
3147
3148 if( i >= TACH_SEST_LEN ) // Link Service Exchange
3149 {
3150 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i); // Don't "abort" LinkService
3151 }
3152
3153 else // SEST Exchange TO -- may post ABTS to Worker Thread Que
3154 {
3155 // (Make sure we don't keep timing it out; let other functions
3156 // complete it or set the timeOut as needed)
3157 Exchanges->fcExchange[i].timeOut = 30000; // seconds default
3158
3159 if( Exchanges->fcExchange[i].type
3160 &
3161 (BLS_ABTS | BLS_ABTS_ACC ) )
3162 {
3163 // For BLS_ABTS*, an upper level might still have
3164 // an outstanding command waiting for low-level completion.
3165 // Also, in the case of a WRITE, we MUST get confirmation
3166 // of either ABTS ACC or RJT before re-using the Exchange.
3167 // It's possible that the RAID cache algorithm can hang
3168 // if we fail to complete a WRITE to a LBA, when a READ
3169 // comes later to that same LBA. Therefore, we must
3170 // ensure that the target verifies receipt of ABTS for
3171 // the exchange
3172
3173 printk("~TO Q'd ABTS (x_ID %Xh)~ ", i);
3174// TriggerHBA( fcChip->Registers.ReMapMemBase);
3175
3176 // On timeout of a ABTS exchange, check to
3177 // see if the FC device has a current valid login.
3178 // If so, restart it.
3179 pLoggedInPort = fcFindLoggedInPort( fcChip,
3180 Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus
3181 0, // DON'T search linked list for FC port id
3182 NULL, // DON'T search linked list for FC WWN
3183 NULL); // DON'T care about end of list
3184
3185 // device exists?
3186 if( pLoggedInPort ) // device exists?
3187 {
3188 if( pLoggedInPort->prli ) // logged in for FCP-SCSI?
3189 {
3190 // attempt to restart the ABTS
3191 printk(" ~restarting ABTS~ ");
3192 cpqfcTSStartExchange( cpqfcHBAdata, i );
3193
3194 }
3195 }
3196 }
3197 else // not an ABTS
3198 {
3199
3200 // We expect the WorkerThread to change the xchng type to
3201 // abort and set appropriate timeout.
3202 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i ); // timed-out
3203 }
3204 }
3205 }
3206 else // time not expired...
3207 {
3208 // decrement timeout: 1 or more seconds left
3209 --Exchanges->fcExchange[i].timeOut;
3210 }
3211 }
3212 }
3213
3214
3215 enable_irq( cpqfcHBAdata->HostAdapter->irq);
3216
3217
3218 CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
3219
3220 cpqfcHBAdata->BoardLock = NULL; // Linux SCSI commands may be queued
3221
3222 // Now, complete any Cmnd we Q'd up while BoardLock was held
3223
3224 CompleteBoardLockCmnd( cpqfcHBAdata);
3225
3226
3227 // restart the timer to run again (1 sec later)
3228Skip:
3229 mod_timer( &cpqfcHBAdata->cpqfcTStimer, jiffies + HZ);
3230
3231 PCI_TRACEO( i, 0xA8)
3232 return;
3233}
3234
3235
3236// put valid FC-AL physical address in spec order
3237static const UCHAR valid_al_pa[]={
3238 0xef, 0xe8, 0xe4, 0xe2,
3239 0xe1, 0xE0, 0xDC, 0xDA,
3240 0xD9, 0xD6, 0xD5, 0xD4,
3241 0xD3, 0xD2, 0xD1, 0xCe,
3242 0xCd, 0xCc, 0xCb, 0xCa,
3243 0xC9, 0xC7, 0xC6, 0xC5,
3244 0xC3, 0xBc, 0xBa, 0xB9,
3245 0xB6, 0xB5, 0xB4, 0xB3,
3246 0xB2, 0xB1, 0xae, 0xad,
3247 0xAc, 0xAb, 0xAa, 0xA9,
3248
3249 0xA7, 0xA6, 0xA5, 0xA3,
3250 0x9f, 0x9e, 0x9d, 0x9b,
3251 0x98, 0x97, 0x90, 0x8f,
3252 0x88, 0x84, 0x82, 0x81,
3253 0x80, 0x7c, 0x7a, 0x79,
3254 0x76, 0x75, 0x74, 0x73,
3255 0x72, 0x71, 0x6e, 0x6d,
3256 0x6c, 0x6b, 0x6a, 0x69,
3257 0x67, 0x66, 0x65, 0x63,
3258 0x5c, 0x5a, 0x59, 0x56,
3259
3260 0x55, 0x54, 0x53, 0x52,
3261 0x51, 0x4e, 0x4d, 0x4c,
3262 0x4b, 0x4a, 0x49, 0x47,
3263 0x46, 0x45, 0x43, 0x3c,
3264 0x3a, 0x39, 0x36, 0x35,
3265 0x34, 0x33, 0x32, 0x31,
3266 0x2e, 0x2d, 0x2c, 0x2b,
3267 0x2a, 0x29, 0x27, 0x26,
3268 0x25, 0x23, 0x1f, 0x1E,
3269 0x1d, 0x1b, 0x18, 0x17,
3270
3271 0x10, 0x0f, 8, 4, 2, 1 }; // ALPA 0 (Fabric) is special case
3272
3273const int number_of_al_pa = (sizeof(valid_al_pa) );
3274
3275
3276
3277// this function looks up an al_pa from the table of valid al_pa's
3278// we decrement from the last decimal loop ID, because soft al_pa
3279// (our typical case) are assigned with highest priority (and high al_pa)
3280// first. See "In-Depth FC-AL", R. Kembel pg. 38
3281// INPUTS:
3282// al_pa - 24 bit port identifier (8 bit al_pa on private loop)
3283// RETURN:
3284// Loop ID - serves are index to array of logged in ports
3285// -1 - invalid al_pa (not all 8 bit values are legal)
3286
3287#if (0)
3288static int GetLoopID( ULONG al_pa )
3289{
3290 int i;
3291
3292 for( i = number_of_al_pa -1; i >= 0; i--) // dec.
3293 {
3294 if( valid_al_pa[i] == (UCHAR)al_pa ) // take lowest 8 bits
3295 return i; // success - found valid al_pa; return decimal LoopID
3296 }
3297 return -1; // failed - not found
3298}
3299#endif
3300
3301extern cpqfc_passthru_private_t *cpqfc_private(Scsi_Request *sr);
3302
3303// Search the singly (forward) linked list "fcPorts" looking for
3304// either the SCSI target (if != -1), port_id (if not NULL),
3305// or WWN (if not null), in that specific order.
3306// If we find a SCSI nexus (from Cmnd arg), set the SCp.phase
3307// field according to VSA or PDU
3308// RETURNS:
3309// Ptr to logged in port struct if found
3310// (NULL if not found)
3311// pLastLoggedInPort - ptr to last struct (for adding new ones)
3312//
3313PFC_LOGGEDIN_PORT fcFindLoggedInPort(
3314 PTACHYON fcChip,
3315 Scsi_Cmnd *Cmnd, // search linked list for Scsi Nexus (channel/target/lun)
3316 ULONG port_id, // search linked list for al_pa, or
3317 UCHAR wwn[8], // search linked list for WWN, or...
3318 PFC_LOGGEDIN_PORT *pLastLoggedInPort )
3319
3320{
3321 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
3322 BOOLEAN target_id_valid=FALSE;
3323 BOOLEAN port_id_valid=FALSE;
3324 BOOLEAN wwn_valid=FALSE;
3325 int i;
3326
3327
3328 if( Cmnd != NULL )
3329 target_id_valid = TRUE;
3330
3331 else if( port_id ) // note! 24-bit NULL address is illegal
3332 port_id_valid = TRUE;
3333
3334 else
3335 {
3336 if( wwn ) // non-null arg? (OK to pass NULL when not searching WWN)
3337 {
3338 for( i=0; i<8; i++) // valid WWN passed? NULL WWN invalid
3339 {
3340 if( wwn[i] != 0 )
3341 wwn_valid = TRUE; // any non-zero byte makes (presumably) valid
3342 }
3343 }
3344 }
3345 // check other options ...
3346
3347
3348 // In case multiple search options are given, we use a priority
3349 // scheme:
3350 // While valid pLoggedIn Ptr
3351 // If port_id is valid
3352 // if port_id matches, return Ptr
3353 // If wwn is valid
3354 // if wwn matches, return Ptr
3355 // Next Ptr in list
3356 //
3357 // Return NULL (not found)
3358
3359
3360 while( pLoggedInPort ) // NULL marks end of list (1st ptr always valid)
3361 {
3362 if( pLastLoggedInPort ) // caller's pointer valid?
3363 *pLastLoggedInPort = pLoggedInPort; // end of linked list
3364
3365 if( target_id_valid )
3366 {
3367 // check Linux Scsi Cmnd for channel/target Nexus match
3368 // (all luns are accessed through matching "pLoggedInPort")
3369 if( (pLoggedInPort->ScsiNexus.target == Cmnd->device->id)
3370 &&
3371 (pLoggedInPort->ScsiNexus.channel == Cmnd->device->channel))
3372 {
3373 // For "passthru" modes, the IOCTL caller is responsible
3374 // for setting the FCP-LUN addressing
3375 if (Cmnd->sc_request != NULL && Cmnd->device->host != NULL &&
3376 Cmnd->device->host->hostdata != NULL &&
3377 is_private_data_of_cpqfc((CPQFCHBA *) Cmnd->device->host->hostdata,
3378 Cmnd->sc_request->upper_private_data)) {
3379 /* This is a passthru... */
3380 cpqfc_passthru_private_t *pd;
3381 pd = Cmnd->sc_request->upper_private_data;
3382 Cmnd->SCp.phase = pd->bus;
3383 // Cmnd->SCp.have_data_in = pd->pdrive;
3384 Cmnd->SCp.have_data_in = Cmnd->device->lun;
3385 } else {
3386 /* This is not a passthru... */
3387
3388 // set the FCP-LUN addressing type
3389 Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;
3390
3391 // set the Device Type we got from the snooped INQUIRY string
3392 Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
3393
3394 // handle LUN masking; if not "default" (illegal) lun value,
3395 // the use it. These lun values are set by a successful
3396 // Report Luns command
3397 if( pLoggedInPort->ScsiNexus.LunMasking == 1)
3398 {
3399 if (Cmnd->device->lun > sizeof(pLoggedInPort->ScsiNexus.lun))
3400 return NULL;
3401 // we KNOW all the valid LUNs... 0xFF is invalid!
3402 Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->device->lun];
3403 if (pLoggedInPort->ScsiNexus.lun[Cmnd->device->lun] == 0xFF)
3404 return NULL;
3405 // printk("xlating lun %d to 0x%02x\n", Cmnd->lun,
3406 // pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
3407 }
3408 else
3409 Cmnd->SCp.have_data_in = Cmnd->device->lun; // Linux & target luns match
3410 }
3411 break; // found it!
3412 }
3413 }
3414
3415 if( port_id_valid ) // look for alpa first
3416 {
3417 if( pLoggedInPort->port_id == port_id )
3418 break; // found it!
3419 }
3420 if( wwn_valid ) // look for wwn second
3421 {
3422
3423 if( !memcmp( &pLoggedInPort->u.ucWWN[0], &wwn[0], 8))
3424 {
3425 // all 8 bytes of WWN match
3426 break; // found it!
3427 }
3428 }
3429
3430 pLoggedInPort = pLoggedInPort->pNextPort; // try next port
3431 }
3432
3433 return pLoggedInPort;
3434}
3435
3436
3437
3438
3439//
3440// We need to examine the SEST table and re-validate
3441// any open Exchanges for this LoggedInPort
3442// To make Tachyon pay attention, Freeze FCP assists,
3443// set VAL bits, Unfreeze FCP assists
3444static void RevalidateSEST( struct Scsi_Host *HostAdapter,
3445 PFC_LOGGEDIN_PORT pLoggedInPort)
3446{
3447 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
3448 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
3449 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
3450 ULONG x_ID;
3451 BOOLEAN TachFroze = FALSE;
3452
3453
3454 // re-validate any SEST exchanges that are permitted
3455 // to survive the link down (e.g., good PDISC performed)
3456 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
3457 {
3458
3459 // If the SEST entry port_id matches the pLoggedInPort,
3460 // we need to re-validate
3461 if( (Exchanges->fcExchange[ x_ID].type == SCSI_IRE)
3462 ||
3463 (Exchanges->fcExchange[ x_ID].type == SCSI_IWE))
3464 {
3465
3466 if( (Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF) // (24-bit port ID)
3467 == pLoggedInPort->port_id)
3468 {
3469// printk(" re-val xID %Xh ", x_ID);
3470 if( !TachFroze ) // freeze if not already frozen
3471 TachFroze |= FreezeTach( cpqfcHBAdata);
3472 fcChip->SEST->u[ x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
3473 }
3474 }
3475 }
3476
3477 if( TachFroze)
3478 {
3479 fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
3480 }
3481}
3482
3483
3484// Complete an Linux Cmnds that we Queued because
3485// our FC link was down (cause immediate retry)
3486
3487static void UnblockScsiDevice( struct Scsi_Host *HostAdapter,
3488 PFC_LOGGEDIN_PORT pLoggedInPort)
3489{
3490 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
3491 Scsi_Cmnd* *SCptr = &cpqfcHBAdata->LinkDnCmnd[0];
3492 Scsi_Cmnd *Cmnd;
3493 int indx;
3494
3495
3496
3497 // if the device was previously "blocked", make sure
3498 // we unblock it so Linux SCSI will resume
3499
3500 pLoggedInPort->device_blocked = FALSE; // clear our flag
3501
3502 // check the Link Down command ptr buffer;
3503 // we can complete now causing immediate retry
3504 for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++)
3505 {
3506 if( *SCptr != NULL ) // scsi command to complete?
3507 {
3508#ifdef DUMMYCMND_DBG
3509 printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr,indx);
3510#endif
3511 Cmnd = *SCptr;
3512
3513
3514 // Are there any Q'd commands for this target?
3515 if( (Cmnd->device->id == pLoggedInPort->ScsiNexus.target)
3516 &&
3517 (Cmnd->device->channel == pLoggedInPort->ScsiNexus.channel) )
3518 {
3519 Cmnd->result = (DID_SOFT_ERROR <<16); // force retry
3520 if( Cmnd->scsi_done == NULL)
3521 {
3522 printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
3523 pLoggedInPort->port_id);
3524 }
3525 else
3526 call_scsi_done(Cmnd);
3527 *SCptr = NULL; // free this slot for next use
3528 }
3529 }
3530 }
3531}
3532
3533
3534//#define WWN_DBG 1
3535
3536static void SetLoginFields(
3537 PFC_LOGGEDIN_PORT pLoggedInPort,
3538 TachFCHDR_GCMND* fchs,
3539 BOOLEAN PDisc,
3540 BOOLEAN Originator)
3541{
3542 LOGIN_PAYLOAD logi; // FC-PH Port Login
3543 PRLI_REQUEST prli; // copy for BIG ENDIAN switch
3544 int i;
3545#ifdef WWN_DBG
3546 ULONG ulBuff;
3547#endif
3548
3549 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
3550
3551 pLoggedInPort->Originator = Originator;
3552 pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
3553
3554 switch( fchs->pl[0] & 0xffff )
3555 {
3556 case 0x00000002: // PLOGI or PDISC ACCept?
3557 if( PDisc ) // PDISC accept
3558 goto PDISC_case;
3559
3560 case 0x00000003: // ELS_PLOGI or ELS_PLOGI_ACC
3561
3562 // Login BB_credit typically 0 for Tachyons
3563 pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
3564
3565 // e.g. 128, 256, 1024, 2048 per FC-PH spec
3566 // We have to use this when setting up SEST Writes,
3567 // since that determines frame size we send.
3568 pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
3569 pLoggedInPort->plogi = TRUE;
3570 pLoggedInPort->pdisc = FALSE;
3571 pLoggedInPort->prli = FALSE; // ELS_PLOGI resets
3572 pLoggedInPort->flogi = FALSE; // ELS_PLOGI resets
3573 pLoggedInPort->logo = FALSE; // ELS_PLOGI resets
3574 pLoggedInPort->LOGO_counter = 0;// ELS_PLOGI resets
3575 pLoggedInPort->LOGO_timer = 0;// ELS_PLOGI resets
3576
3577 // was this PLOGI to a Fabric?
3578 if( pLoggedInPort->port_id == 0xFFFFFC ) // well know address
3579 pLoggedInPort->flogi = TRUE;
3580
3581
3582 for( i=0; i<8; i++) // copy the LOGIN port's WWN
3583 pLoggedInPort->u.ucWWN[i] = logi.port_name[i];
3584
3585#ifdef WWN_DBG
3586 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3587 if( pLoggedInPort->Originator)
3588 printk("o");
3589 else
3590 printk("r");
3591 printk("PLOGI port_id %Xh, WWN %08X",
3592 pLoggedInPort->port_id, ulBuff);
3593
3594 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3595 printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
3596#endif
3597 break;
3598
3599
3600
3601
3602 case 0x00000005: // ELS_LOGO (logout)
3603
3604
3605 pLoggedInPort->plogi = FALSE;
3606 pLoggedInPort->pdisc = FALSE;
3607 pLoggedInPort->prli = FALSE; // ELS_PLOGI resets
3608 pLoggedInPort->flogi = FALSE; // ELS_PLOGI resets
3609 pLoggedInPort->logo = TRUE; // ELS_PLOGI resets
3610 pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
3611 pLoggedInPort->LOGO_timer = 0;
3612#ifdef WWN_DBG
3613 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3614 if( pLoggedInPort->Originator)
3615 printk("o");
3616 else
3617 printk("r");
3618 printk("LOGO port_id %Xh, WWN %08X",
3619 pLoggedInPort->port_id, ulBuff);
3620
3621 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3622 printk("%08Xh\n", ulBuff);
3623#endif
3624 break;
3625
3626
3627
3628PDISC_case:
3629 case 0x00000050: // ELS_PDISC or ELS_PDISC_ACC
3630 pLoggedInPort->LOGO_timer = 0; // stop the time-out
3631
3632 pLoggedInPort->prli = TRUE; // ready to accept FCP-SCSI I/O
3633
3634
3635
3636#ifdef WWN_DBG
3637 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3638 if( pLoggedInPort->Originator)
3639 printk("o");
3640 else
3641 printk("r");
3642 printk("PDISC port_id %Xh, WWN %08X",
3643 pLoggedInPort->port_id, ulBuff);
3644
3645 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3646 printk("%08Xh\n", ulBuff);
3647#endif
3648
3649
3650
3651 break;
3652
3653
3654
3655 case 0x1020L: // PRLI?
3656 case 0x1002L: // PRLI ACCept?
3657 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
3658
3659 pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
3660 pLoggedInPort->prli = TRUE; // PLOGI resets, PDISC doesn't
3661
3662 pLoggedInPort->pdisc = TRUE; // expect to send (or receive) PDISC
3663 // next time
3664 pLoggedInPort->LOGO_timer = 0; // will be set next LinkDown
3665#ifdef WWN_DBG
3666 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3667 if( pLoggedInPort->Originator)
3668 printk("o");
3669 else
3670 printk("r");
3671 printk("PRLI port_id %Xh, WWN %08X",
3672 pLoggedInPort->port_id, ulBuff);
3673
3674 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3675 printk("%08Xh\n", ulBuff);
3676#endif
3677
3678 break;
3679
3680 }
3681
3682 return;
3683}
3684
3685
3686
3687
3688
3689
3690static void BuildLinkServicePayload( PTACHYON fcChip, ULONG type, void* payload)
3691{
3692 LOGIN_PAYLOAD *plogi; // FC-PH Port Login
3693 LOGIN_PAYLOAD PlogiPayload; // copy for BIG ENDIAN switch
3694 PRLI_REQUEST *prli; // FCP-SCSI Process Login
3695 PRLI_REQUEST PrliPayload; // copy for BIG ENDIAN switch
3696 LOGOUT_PAYLOAD *logo;
3697 LOGOUT_PAYLOAD LogoutPayload;
3698// PRLO_REQUEST *prlo;
3699// PRLO_REQUEST PrloPayload;
3700 REJECT_MESSAGE rjt, *prjt;
3701
3702 memset( &PlogiPayload, 0, sizeof( PlogiPayload));
3703 plogi = &PlogiPayload; // load into stack buffer,
3704 // then BIG-ENDIAN switch a copy to caller
3705
3706
3707 switch( type ) // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
3708 {
3709 case ELS_FDISC:
3710 case ELS_FLOGI:
3711 case ELS_PLOGI_ACC: // FC-PH PORT Login Accept
3712 case ELS_PLOGI: // FC-PH PORT Login
3713 case ELS_PDISC: // FC-PH2 Port Discovery - same payload as ELS_PLOGI
3714 plogi->login_cmd = LS_PLOGI;
3715 if( type == ELS_PDISC)
3716 plogi->login_cmd = LS_PDISC;
3717 else if( type == ELS_PLOGI_ACC )
3718 plogi->login_cmd = LS_ACC;
3719
3720 plogi->cmn_services.bb_credit = 0x00;
3721 plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
3722 plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
3723 plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
3724 plogi->cmn_services.common_features = CONTINUOSLY_INCREASING |
3725 RANDOM_RELATIVE_OFFSET;
3726
3727 // fill in with World Wide Name based Port Name - 8 UCHARs
3728 // get from Tach registers WWN hi & lo
3729 LoadWWN( fcChip, plogi->port_name, 0);
3730 // fill in with World Wide Name based Node/Fabric Name - 8 UCHARs
3731 // get from Tach registers WWN hi & lo
3732 LoadWWN( fcChip, plogi->node_name, 1);
3733
3734 // For Seagate Drives.
3735 //
3736 plogi->cmn_services.common_features |= 0x800;
3737 plogi->cmn_services.rel_offset = 0xFE;
3738 plogi->cmn_services.concurrent_seq = 1;
3739 plogi->class1.service_options = 0x00;
3740 plogi->class2.service_options = 0x00;
3741 plogi->class3.service_options = CLASS_VALID;
3742 plogi->class3.initiator_control = 0x00;
3743 plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
3744 plogi->class3.recipient_control =
3745 ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
3746 plogi->class3.concurrent_sequences = 1;
3747 plogi->class3.open_sequences = 1;
3748 plogi->vendor_id[0] = 'C'; plogi->vendor_id[1] = 'Q';
3749 plogi->vendor_version[0] = 'C'; plogi->vendor_version[1] = 'Q';
3750 plogi->vendor_version[2] = ' '; plogi->vendor_version[3] = '0';
3751 plogi->vendor_version[4] = '0'; plogi->vendor_version[5] = '0';
3752
3753
3754 // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
3755 if( (type == ELS_FLOGI) || (type == ELS_FDISC) )
3756 {
3757 if( type == ELS_FLOGI )
3758 plogi->login_cmd = LS_FLOGI;
3759 else
3760 plogi->login_cmd = LS_FDISC;
3761
3762 plogi->cmn_services.lowest_ver = 0x20;
3763 plogi->cmn_services.common_features = 0x0800;
3764 plogi->cmn_services.rel_offset = 0;
3765 plogi->cmn_services.concurrent_seq = 0;
3766
3767 plogi->class3.service_options = 0x8800;
3768 plogi->class3.rx_data_size = 0;
3769 plogi->class3.recipient_control = 0;
3770 plogi->class3.concurrent_sequences = 0;
3771 plogi->class3.open_sequences = 0;
3772 }
3773
3774 // copy back to caller's buff, w/ BIG ENDIAN swap
3775 BigEndianSwap( (UCHAR*)&PlogiPayload, payload, sizeof(PlogiPayload));
3776 break;
3777
3778
3779 case ELS_ACC: // generic Extended Link Service ACCept
3780 plogi->login_cmd = LS_ACC;
3781 // copy back to caller's buff, w/ BIG ENDIAN swap
3782 BigEndianSwap( (UCHAR*)&PlogiPayload, payload, 4);
3783 break;
3784
3785
3786
3787 case ELS_SCR: // Fabric State Change Registration
3788 {
3789 SCR_PL scr; // state change registration
3790
3791 memset( &scr, 0, sizeof(scr));
3792
3793 scr.command = LS_SCR; // 0x62000000
3794 // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
3795 scr.function = 3; // 1 = Events detected by Fabric
3796 // 2 = N_Port detected registration
3797 // 3 = Full registration
3798
3799 // copy back to caller's buff, w/ BIG ENDIAN swap
3800 BigEndianSwap( (UCHAR*)&scr, payload, sizeof(SCR_PL));
3801 }
3802
3803 break;
3804
3805
3806 case FCS_NSR: // Fabric Name Service Request
3807 {
3808 NSR_PL nsr; // Name Server Req. payload
3809
3810 memset( &nsr, 0, sizeof(NSR_PL));
3811
3812 // see Brocade Fabric Programming Guide,
3813 // Rev 1.3, pg 4-44
3814 nsr.CT_Rev = 0x01000000;
3815 nsr.FCS_Type = 0xFC020000;
3816 nsr.Command_code = 0x01710000;
3817 nsr.FCP = 8;
3818
3819 // copy back to caller's buff, w/ BIG ENDIAN swap
3820 BigEndianSwap( (UCHAR*)&nsr, payload, sizeof(NSR_PL));
3821 }
3822
3823 break;
3824
3825
3826
3827
3828 case ELS_LOGO: // FC-PH PORT LogOut
3829 logo = &LogoutPayload; // load into stack buffer,
3830 // then BIG-ENDIAN switch a copy to caller
3831 logo->cmd = LS_LOGO;
3832 // load the 3 UCHARs of the node name
3833 // (if private loop, upper two UCHARs 0)
3834 logo->reserved = 0;
3835
3836 logo->n_port_identifier[0] = (UCHAR)(fcChip->Registers.my_al_pa);
3837 logo->n_port_identifier[1] =
3838 (UCHAR)(fcChip->Registers.my_al_pa>>8);
3839 logo->n_port_identifier[2] =
3840 (UCHAR)(fcChip->Registers.my_al_pa>>16);
3841 // fill in with World Wide Name based Port Name - 8 UCHARs
3842 // get from Tach registers WWN hi & lo
3843 LoadWWN( fcChip, logo->port_name, 0);
3844
3845 BigEndianSwap( (UCHAR*)&LogoutPayload,
3846 payload, sizeof(LogoutPayload) ); // 16 UCHAR struct
3847 break;
3848
3849
3850 case ELS_LOGO_ACC: // Logout Accept (FH-PH pg 149, table 74)
3851 logo = &LogoutPayload; // load into stack buffer,
3852 // then BIG-ENDIAN switch a copy to caller
3853 logo->cmd = LS_ACC;
3854 BigEndianSwap( (UCHAR*)&LogoutPayload, payload, 4 ); // 4 UCHAR cmnd
3855 break;
3856
3857
3858 case ELS_RJT: // ELS_RJT link service reject (FH-PH pg 155)
3859
3860 prjt = (REJECT_MESSAGE*)payload; // pick up passed data
3861 rjt.command_code = ELS_RJT;
3862 // reverse fields, because of Swap that follows...
3863 rjt.vendor = prjt->reserved; // vendor specific
3864 rjt.explain = prjt->reason; //
3865 rjt.reason = prjt->explain; //
3866 rjt.reserved = prjt->vendor; //
3867 // BIG-ENDIAN switch a copy to caller
3868 BigEndianSwap( (UCHAR*)&rjt, payload, 8 ); // 8 UCHAR cmnd
3869 break;
3870
3871
3872
3873
3874
3875 case ELS_PRLI_ACC: // Process Login ACCept
3876 case ELS_PRLI: // Process Login
3877 case ELS_PRLO: // Process Logout
3878 memset( &PrliPayload, 0, sizeof( PrliPayload));
3879 prli = &PrliPayload; // load into stack buffer,
3880
3881 if( type == ELS_PRLI )
3882 prli->cmd = 0x20; // Login
3883 else if( type == ELS_PRLO )
3884 prli->cmd = 0x21; // Logout
3885 else if( type == ELS_PRLI_ACC )
3886 {
3887 prli->cmd = 0x02; // Login ACCept
3888 prli->valid = REQUEST_EXECUTED;
3889 }
3890
3891
3892 prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
3893 prli->fcp_info = READ_XFER_RDY;
3894 prli->page_length = 0x10;
3895 prli->payload_length = 20;
3896 // Can be initiator AND target
3897
3898 if( fcChip->Options.initiator )
3899 prli->fcp_info |= INITIATOR_FUNCTION;
3900 if( fcChip->Options.target )
3901 prli->fcp_info |= TARGET_FUNCTION;
3902
3903 BigEndianSwap( (UCHAR*)&PrliPayload, payload, prli->payload_length);
3904 break;
3905
3906
3907
3908 default: // no can do - programming error
3909 printk(" BuildLinkServicePayload unknown!\n");
3910 break;
3911 }
3912}
3913
3914// loads 8 UCHARs for PORT name or NODE name base on
3915// controller's WWN.
3916void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type)
3917{
3918 UCHAR* bPtr, i;
3919
3920 switch( type )
3921 {
3922 case 0: // Port_Name
3923 bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
3924 for( i =0; i<4; i++)
3925 dest[i] = *bPtr++;
3926 bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
3927 for( i =4; i<8; i++)
3928 dest[i] = *bPtr++;
3929 break;
3930 case 1: // Node/Fabric _Name
3931 bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
3932 for( i =0; i<4; i++)
3933 dest[i] = *bPtr++;
3934 bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
3935 for( i =4; i<8; i++)
3936 dest[i] = *bPtr++;
3937 break;
3938 }
3939
3940}
3941
3942
3943
3944// We check the Port Login payload for required values. Note that
3945// ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload.
3946
3947
3948int verify_PLOGI( PTACHYON fcChip,
3949 TachFCHDR_GCMND* fchs,
3950 ULONG* reject_explain)
3951{
3952 LOGIN_PAYLOAD login;
3953
3954 // source, dest, len (should be mult. of 4)
3955 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&login, sizeof(login));
3956
3957 // check FC version
3958 // if other port's highest supported version
3959 // is less than our lowest, and
3960 // if other port's lowest
3961 if( login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver ||
3962 login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver )
3963 {
3964 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
3965 return LOGICAL_ERROR;
3966 }
3967
3968 // Receive Data Field Size must be >=128
3969 // per FC-PH
3970 if (login.cmn_services.bb_rx_size < 128)
3971 {
3972 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
3973 return LOGICAL_ERROR;
3974 }
3975
3976 // Only check Class 3 params
3977 if( login.class3.service_options & CLASS_VALID)
3978 {
3979 if (login.class3.rx_data_size < 128)
3980 {
3981 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INVALID_CSP);
3982 return LOGICAL_ERROR;
3983 }
3984 if( login.class3.initiator_control & XID_REQUIRED)
3985 {
3986 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INITIATOR_CTL_ERROR);
3987 return LOGICAL_ERROR;
3988 }
3989 }
3990 return 0; // success
3991}
3992
3993
3994
3995
3996int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain)
3997{
3998 PRLI_REQUEST prli; // buffer for BIG ENDIAN
3999
4000 // source, dest, len (should be mult. of 4)
4001 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
4002
4003 if( prli.fcp_info == 0 ) // i.e., not target or initiator?
4004 {
4005 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
4006 return LOGICAL_ERROR;
4007 }
4008
4009 return 0; // success
4010}
4011
4012
4013// SWAP UCHARs as required by Fibre Channel (i.e. BIG ENDIAN)
4014// INPUTS:
4015// source - ptr to LITTLE ENDIAN ULONGS
4016// cnt - number of UCHARs to switch (should be mult. of ULONG)
4017// OUTPUTS:
4018// dest - ptr to BIG ENDIAN copy
4019// RETURN:
4020// none
4021//
4022void BigEndianSwap( UCHAR *source, UCHAR *dest, USHORT cnt)
4023{
4024 int i,j;
4025
4026 source+=3; // start at MSB of 1st ULONG
4027 for( j=0; j < cnt; j+=4, source+=4, dest+=4) // every ULONG
4028 {
4029 for( i=0; i<4; i++) // every UCHAR in ULONG
4030 *(dest+i) = *(source-i);
4031 }
4032}
4033
4034
4035
4036
4037// Build FC Exchanges............
4038
4039static void buildFCPstatus(
4040 PTACHYON fcChip,
4041 ULONG ExchangeID);
4042
4043static LONG FindFreeExchange( PTACHYON fcChip, ULONG type );
4044
4045static ULONG build_SEST_sgList(
4046 struct pci_dev *pcidev,
4047 ULONG *SESTalPairStart,
4048 Scsi_Cmnd *Cmnd,
4049 ULONG *sgPairs,
4050 PSGPAGES *sgPages_head // link list of TL Ext. S/G pages from O/S Pool
4051);
4052
4053static int build_FCP_payload( Scsi_Cmnd *Cmnd,
4054 UCHAR* payload, ULONG type, ULONG fcp_dl );
4055
4056
4057/*
4058 IRB
4059 ERQ __________________
4060 | | / | Req_A_SFS_Len | ____________________
4061 |----------| / | Req_A_SFS_Addr |------->| Reserved |
4062 | IRB | / | Req_A_D_ID | | SOF EOF TimeStamp |
4063 |-----------/ | Req_A_SEST_Index |-+ | R_CTL | D_ID |
4064 | IRB | | Req_B... | | | CS_CTL| S_ID |
4065 |-----------\ | | | | TYPE | F_CTL |
4066 | IRB | \ | | | | SEQ_ID | SEQ_CNT |
4067 |----------- \ | | +-->+--| OX_ID | RX_ID |
4068 | | \ |__________________| | | RO |
4069 | | pl (payload/cmnd) |
4070 | | ..... |
4071 | |___________________|
4072 |
4073 |
4074+-------------------------------------------+
4075|
4076|
4077| e.g. IWE
4078| SEST __________________ for FCP_DATA
4079| | | / | | Hdr_Len | ____________________
4080| |----------| / | Hdr_Addr_Addr |------->| Reserved |
4081| | [0] | / |Remote_ID| RSP_Len| | SOF EOF TimeStamp |
4082| |-----------/ | RSP_Addr |---+ | R_CTL | D_ID |
4083+-> [1] | | | Buff_Off | | | CS_CTL| S_ID |
4084 |-----------\ |BuffIndex| Link | | | TYPE | F_CTL |
4085 | [2] | \ | Rsvd | RX_ID | | | SEQ_ID | SEQ_CNT |
4086 |----------- \ | Data_Len | | | OX_ID | RX_ID |
4087 | ... | \ | Exp_RO | | | RO |
4088 |----------| | Exp_Byte_Cnt | | |___________________|
4089 | SEST_LEN | +--| Len | |
4090 |__________| | | Address | |
4091 | | ... | | for FCP_RSP
4092 | |__________________| | ____________________
4093 | +----| Reserved |
4094 | | SOF EOF TimeStamp |
4095 | | R_CTL | D_ID |
4096 | | CS_CTL| S_ID |
4097 +--- local or extended | .... |
4098 scatter/gather lists
4099 defining upper-layer
4100 data (e.g. from user's App)
4101
4102
4103*/
4104// All TachLite commands must start with a SFS (Single Frame Sequence)
4105// command. In the simplest case (a NOP Basic Link command),
4106// only one frame header and ERQ entry is required. The most complex
4107// case is the SCSI assisted command, which requires an ERQ entry,
4108// SEST entry, and several frame headers and data buffers all
4109// logically linked together.
4110// Inputs:
4111// cpqfcHBAdata - controller struct
4112// type - PLOGI, SCSI_IWE, etc.
4113// InFCHS - Incoming Tachlite FCHS which prompted this exchange
4114// (only s_id set if we are originating)
4115// Data - PVOID to data struct consistent with "type"
4116// fcExchangeIndex - pointer to OX/RD ID value of built exchange
4117// Return:
4118// fcExchangeIndex - OX/RD ID value if successful
4119// 0 - success
4120// INVALID_ARGS - NULL/ invalid passed args
4121// BAD_ALPA - Bad source al_pa address
4122// LNKDWN_OSLS - Link Down (according to this controller)
4123// OUTQUE_FULL - Outbound Que full
4124// DRIVERQ_FULL - controller's Exchange array full
4125// SEST_FULL - SEST table full
4126//
4127// Remarks:
4128// Psuedo code:
4129// Check for NULL pointers / bad args
4130// Build outgoing FCHS - the header/payload struct
4131// Build IRB (for ERQ entry)
4132// if SCSI command, build SEST entry (e.g. IWE, TRE,...)
4133// return success
4134
4135//sbuildex
4136ULONG cpqfcTSBuildExchange(
4137 CPQFCHBA *cpqfcHBAdata,
4138 ULONG type, // e.g. PLOGI
4139 TachFCHDR_GCMND* InFCHS, // incoming FCHS
4140 void *Data, // the CDB, scatter/gather, etc.
4141 LONG *fcExchangeIndex ) // points to allocated exchange,
4142{
4143 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
4144 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
4145 ULONG ulStatus = 0; // assume OK
4146 USHORT ox_ID, rx_ID=0xFFFF;
4147 ULONG SfsLen=0L;
4148 TachLiteIRB* pIRB;
4149 IRBflags IRB_flags;
4150 UCHAR *pIRB_flags = (UCHAR*)&IRB_flags;
4151 TachFCHDR_GCMND* CMDfchs;
4152 TachFCHDR* dataHDR; // 32 byte HEADER ONLY FCP-DATA buffer
4153 TachFCHDR_RSP* rspHDR; // 32 byte header + RSP payload
4154 Scsi_Cmnd *Cmnd = (Scsi_Cmnd*)Data; // Linux Scsi CDB, S/G, ...
4155 TachLiteIWE* pIWE;
4156 TachLiteIRE* pIRE;
4157 TachLiteTWE* pTWE;
4158 TachLiteTRE* pTRE;
4159 ULONG fcp_dl; // total byte length of DATA transferred
4160 ULONG fl; // frame length (FC frame size, 128, 256, 512, 1024)
4161 ULONG sgPairs; // number of valid scatter/gather pairs
4162 int FCP_SCSI_command;
4163 BA_ACC_PAYLOAD *ba_acc;
4164 BA_RJT_PAYLOAD *ba_rjt;
4165
4166 // check passed ARGS
4167 if( !fcChip->ERQ ) // NULL ptr means uninitialized Tachlite chip
4168 return INVALID_ARGS;
4169
4170
4171 if( type == SCSI_IRE ||
4172 type == SCSI_TRE ||
4173 type == SCSI_IWE ||
4174 type == SCSI_TWE)
4175 FCP_SCSI_command = 1;
4176
4177 else
4178 FCP_SCSI_command = 0;
4179
4180
4181 // for commands that pass payload data (e.g. SCSI write)
4182 // examine command struct - verify that the
4183 // length of s/g buffers is adequate for total payload
4184 // length (end of list is NULL address)
4185
4186 if( FCP_SCSI_command )
4187 {
4188 if( Data ) // must have data descriptor (S/G list -- at least
4189 // one address with at least 1 byte of data)
4190 {
4191 // something to do (later)?
4192 }
4193
4194 else
4195 return INVALID_ARGS; // invalid DATA ptr
4196 }
4197
4198
4199
4200 // we can build an Exchange for later Queuing (on the TL chip)
4201 // if an empty slot is available in the DevExt for this controller
4202 // look for available Exchange slot...
4203
4204 if( type != FCP_RESPONSE &&
4205 type != BLS_ABTS &&
4206 type != BLS_ABTS_ACC ) // already have Exchange slot!
4207 *fcExchangeIndex = FindFreeExchange( fcChip, type );
4208
4209 if( *fcExchangeIndex != -1 ) // Exchange is available?
4210 {
4211 // assign tmp ptr (shorthand)
4212 CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs;
4213
4214 if( Cmnd != NULL ) // (necessary for ABTS cases)
4215 {
4216 Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
4217 Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort =
4218 fcFindLoggedInPort( fcChip,
4219 Exchanges->fcExchange[ *fcExchangeIndex].Cmnd, // find Scsi Nexus
4220 0, // DON'T search linked list for FC port id
4221 NULL, // DON'T search linked list for FC WWN
4222 NULL); // DON'T care about end of list
4223
4224 }
4225
4226
4227 // Build the command frame header (& data) according
4228 // to command type
4229
4230 // fields common for all SFS frame types
4231 CMDfchs->reserved = 0L; // must clear
4232 CMDfchs->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; LCr=0, no TS
4233
4234 // get the destination port_id from incoming FCHS
4235 // (initialized before calling if we're Originator)
4236 // Frame goes to port it was from - the source_id
4237
4238 CMDfchs->d_id = InFCHS->s_id &0xFFFFFF; // destination (add R_CTL later)
4239 CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4240
4241
4242 // now enter command-specific fields
4243 switch( type )
4244 {
4245
4246 case BLS_NOP: // FC defined basic link service command NO-OP
4247 // ensure unique X_IDs! (use tracking function)
4248
4249 *pIRB_flags = 0; // clear IRB flags
4250 IRB_flags.SFA = 1; // send SFS (not SEST index)
4251 SfsLen = *pIRB_flags;
4252
4253 SfsLen <<= 24; // shift flags to MSB
4254 SfsLen += 32L; // add len to LSB (header only - no payload)
4255
4256 // TYPE[31-24] 00 Basic Link Service
4257 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4258 CMDfchs->d_id |= 0x80000000L; // R_CTL = 80 for NOP (Basic Link Ser.)
4259 CMDfchs->f_ctl = 0x00310000L; // xchng originator, 1st seq,....
4260 CMDfchs->seq_cnt = 0x0L;
4261 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID for now; OX_ID on start
4262 CMDfchs->ro = 0x0L; // relative offset (n/a)
4263 CMDfchs->pl[0] = 0xaabbccddL; // words 8-15 frame data payload (n/a)
4264 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // seconds
4265 // (NOP should complete ~instantly)
4266 break;
4267
4268
4269
4270
4271 case BLS_ABTS_ACC: // Abort Sequence ACCept
4272 *pIRB_flags = 0; // clear IRB flags
4273 IRB_flags.SFA = 1; // send SFS (not SEST index)
4274 SfsLen = *pIRB_flags;
4275
4276 SfsLen <<= 24; // shift flags to MSB
4277 SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
4278
4279 CMDfchs->d_id |= 0x84000000L; // R_CTL = 84 for BASIC ACCept
4280 // TYPE[31-24] 00 Basic Link Service
4281 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4282 CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
4283 // CMDfchs->seq_id & count might be set from DataHdr?
4284 CMDfchs->ro = 0x0L; // relative offset (n/a)
4285 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
4286 // (Timeout in case of weird error)
4287
4288 // now set the ACCept payload...
4289 ba_acc = (BA_ACC_PAYLOAD*)&CMDfchs->pl[0];
4290 memset( ba_acc, 0, sizeof( BA_ACC_PAYLOAD));
4291 // Since PLDA requires (only) entire Exchange aborts, we don't need
4292 // to worry about what the last sequence was.
4293
4294 // We expect that a "target" task is accepting the abort, so we
4295 // can use the OX/RX ID pair
4296 ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
4297
4298 // source, dest, #bytes
4299 BigEndianSwap((UCHAR *)&CMDfchs->ox_rx_id, (UCHAR *)&ba_acc->ox_rx_id, 4);
4300
4301 ba_acc->low_seq_cnt = 0;
4302 ba_acc->high_seq_cnt = 0xFFFF;
4303
4304
4305 break;
4306
4307
4308 case BLS_ABTS_RJT: // Abort Sequence ACCept
4309 *pIRB_flags = 0; // clear IRB flags
4310 IRB_flags.SFA = 1; // send SFS (not SEST index)
4311 SfsLen = *pIRB_flags;
4312
4313 SfsLen <<= 24; // shift flags to MSB
4314 SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
4315
4316 CMDfchs->d_id |= 0x85000000L; // R_CTL = 85 for BASIC ReJecT
4317 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4318 // TYPE[31-24] 00 Basic Link Service
4319 CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
4320 // CMDfchs->seq_id & count might be set from DataHdr?
4321 CMDfchs->ro = 0x0L; // relative offset (n/a)
4322 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
4323 // (Timeout in case of weird error)
4324
4325 CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
4326
4327 // now set the ReJecT payload...
4328 ba_rjt = (BA_RJT_PAYLOAD*)&CMDfchs->pl[0];
4329 memset( ba_rjt, 0, sizeof( BA_RJT_PAYLOAD));
4330
4331 // We expect that a "target" task couldn't find the Exhange in the
4332 // array of active exchanges, so we use a new LinkService X_ID.
4333 // See Reject payload description in FC-PH (Rev 4.3), pg. 140
4334 ba_rjt->reason_code = 0x09; // "unable to perform command request"
4335 ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
4336
4337
4338 break;
4339
4340
4341 case BLS_ABTS: // FC defined basic link service command ABTS
4342 // Abort Sequence
4343
4344
4345 *pIRB_flags = 0; // clear IRB flags
4346 IRB_flags.SFA = 1; // send SFS (not SEST index)
4347 SfsLen = *pIRB_flags;
4348
4349 SfsLen <<= 24; // shift flags to MSB
4350 SfsLen += 32L; // add len to LSB (header only - no payload)
4351
4352 // TYPE[31-24] 00 Basic Link Service
4353 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4354 CMDfchs->d_id |= 0x81000000L; // R_CTL = 81 for ABTS
4355 CMDfchs->f_ctl = 0x00110000L; // xchnge originator, last seq, xfer SI
4356 // CMDfchs->seq_id & count might be set from DataHdr?
4357 CMDfchs->ro = 0x0L; // relative offset (n/a)
4358 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4359 // (ABTS must timeout when responder is gone)
4360 break;
4361
4362
4363
4364 case FCS_NSR: // Fabric Name Service Request
4365 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
4366
4367
4368 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4369 // OX_ID, linked to Driver Transaction ID
4370 // (fix-up at Queing time)
4371 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
4372 // OX_ID set at ERQueing time
4373 *pIRB_flags = 0; // clear IRB flags
4374 IRB_flags.SFA = 1; // send SFS (not SEST index)
4375 SfsLen = *pIRB_flags;
4376
4377 SfsLen <<= 24; // shift flags to MSB
4378 SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
4379
4380 CMDfchs->d_id |= 0x02000000L; // R_CTL = 02 for -
4381 // Name Service Request: Unsolicited
4382 // TYPE[31-24] 01 Extended Link Service
4383 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4384 CMDfchs->f_ctl = 0x20210000L;
4385 // OX_ID will be fixed-up at Tachyon enqueing time
4386 CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
4387 CMDfchs->ro = 0x0L; // relative offset (n/a)
4388
4389 BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4390
4391
4392
4393
4394
4395
4396 break;
4397
4398
4399
4400
4401 case ELS_PLOGI: // FC-PH extended link service command Port Login
4402 // (May, 2000)
4403 // NOTE! This special case facilitates SANMark testing. The SANMark
4404 // test script for initialization-timeout.fcal.SANMark-1.fc
4405 // "eats" the OPN() primitive without issuing an R_RDY, causing
4406 // Tachyon to report LST (loop state timeout), which causes a
4407 // LIP. To avoid this, simply send out the frame (i.e. assuming a
4408 // buffer credit of 1) without waiting for R_RDY. Many FC devices
4409 // (other than Tachyon) have been doing this for years. We don't
4410 // ever want to do this for non-Link Service frames unless the
4411 // other device really did report non-zero login BB credit (i.e.
4412 // in the PLOGI ACCept frame).
4413// CMDfchs->sof_eof |= 0x00000400L; // LCr=1
4414
4415 case ELS_FDISC: // Fabric Discovery (Login)
4416 case ELS_FLOGI: // Fabric Login
4417 case ELS_SCR: // Fabric State Change Registration
4418 case ELS_LOGO: // FC-PH extended link service command Port Logout
4419 case ELS_PDISC: // FC-PH extended link service cmnd Port Discovery
4420 case ELS_PRLI: // FC-PH extended link service cmnd Process Login
4421
4422 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
4423
4424
4425 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4426 // OX_ID, linked to Driver Transaction ID
4427 // (fix-up at Queing time)
4428 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
4429 // OX_ID set at ERQueing time
4430 *pIRB_flags = 0; // clear IRB flags
4431 IRB_flags.SFA = 1; // send SFS (not SEST index)
4432 SfsLen = *pIRB_flags;
4433
4434 SfsLen <<= 24; // shift flags to MSB
4435 if( type == ELS_LOGO )
4436 SfsLen += (32L + 16L); // add len (header & PLOGI payload)
4437 else if( type == ELS_PRLI )
4438 SfsLen += (32L + 20L); // add len (header & PRLI payload)
4439 else if( type == ELS_SCR )
4440 SfsLen += (32L + sizeof(SCR_PL)); // add len (header & SCR payload)
4441 else
4442 SfsLen += (32L + 116L); // add len (header & PLOGI payload)
4443
4444 CMDfchs->d_id |= 0x22000000L; // R_CTL = 22 for -
4445 // Extended Link_Data: Unsolicited Control
4446 // TYPE[31-24] 01 Extended Link Service
4447 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4448 CMDfchs->f_ctl = 0x01210000L;
4449 // OX_ID will be fixed-up at Tachyon enqueing time
4450 CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
4451 CMDfchs->ro = 0x0L; // relative offset (n/a)
4452
4453 BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4454
4455 break;
4456
4457
4458
4459 case ELS_LOGO_ACC: // FC-PH extended link service logout accept
4460 case ELS_RJT: // extended link service reject (add reason)
4461 case ELS_ACC: // ext. link service generic accept
4462 case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
4463 case ELS_PRLI_ACC: // ext. link service process login accept
4464
4465
4466 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // assume done
4467 // ensure unique X_IDs! (use tracking function)
4468 // OX_ID from initiator cmd
4469 ox_ID = (USHORT)(InFCHS->ox_rx_id >> 16);
4470 rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
4471
4472 *pIRB_flags = 0; // clear IRB flags
4473 IRB_flags.SFA = 1; // send SFS (not SEST index)
4474 SfsLen = *pIRB_flags;
4475
4476 SfsLen <<= 24; // shift flags to MSB
4477 if( type == ELS_RJT )
4478 {
4479 SfsLen += (32L + 8L); // add len (header + payload)
4480
4481 // ELS_RJT reason codes (utilize unused "reserved" field)
4482 CMDfchs->pl[0] = 1;
4483 CMDfchs->pl[1] = InFCHS->reserved;
4484
4485 }
4486 else if( (type == ELS_LOGO_ACC) || (type == ELS_ACC) )
4487 SfsLen += (32L + 4L); // add len (header + payload)
4488 else if( type == ELS_PLOGI_ACC )
4489 SfsLen += (32L + 116L); // add len (header + payload)
4490 else if( type == ELS_PRLI_ACC )
4491 SfsLen += (32L + 20L); // add len (header + payload)
4492
4493 CMDfchs->d_id |= 0x23000000L; // R_CTL = 23 for -
4494 // Extended Link_Data: Control Reply
4495 // TYPE[31-24] 01 Extended Link Service
4496 // f_ctl[23:0] exchg responder, last seq, e_s, tsi
4497 CMDfchs->f_ctl = 0x01990000L;
4498 CMDfchs->seq_cnt = 0x0L;
4499 CMDfchs->ox_rx_id = 0L; // clear
4500 CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
4501 CMDfchs->ox_rx_id <<= 16; // shift them
4502
4503 CMDfchs->ro = 0x0L; // relative offset (n/a)
4504
4505 BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4506
4507 break;
4508
4509
4510 // Fibre Channel SCSI 'originator' sequences...
4511 // (originator means 'initiator' in FCP-SCSI)
4512
4513 case SCSI_IWE: // TachLite Initiator Write Entry
4514 {
4515 PFC_LOGGEDIN_PORT pLoggedInPort =
4516 Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort;
4517
4518 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
4519 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // FC2 timeout
4520
4521 // first, build FCP_CMND
4522 // unique X_ID fix-ups in StartExchange
4523
4524 *pIRB_flags = 0; // clear IRB flags
4525 IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
4526
4527 // NOTE: unlike FC LinkService login frames, normal
4528 // SCSI commands are sent without outgoing verification
4529 IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
4530 SfsLen = *pIRB_flags;
4531
4532 SfsLen <<= 24; // shift flags to MSB
4533 SfsLen += 64L; // add len to LSB (header & CMND payload)
4534
4535 CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
4536
4537 // TYPE[31-24] 8 for FCP SCSI
4538 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4539 // valid RO
4540 CMDfchs->f_ctl = 0x08210008L;
4541 CMDfchs->seq_cnt = 0x0L;
4542 CMDfchs->ox_rx_id = 0L; // clear for now (-or- in later)
4543 CMDfchs->ro = 0x0L; // relative offset (n/a)
4544
4545 // now, fill out FCP-DATA header
4546 // (use buffer inside SEST object)
4547 dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
4548 dataHDR->reserved = 0L; // must clear
4549 dataHDR->sof_eof = 0x75002000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
4550 dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
4551 dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4552 // TYPE[31-24] 8 for FCP SCSI
4553 // f_ctl[23:0] xfer S.I.| valid RO
4554 dataHDR->f_ctl = 0x08010008L;
4555 dataHDR->seq_cnt = 0x02000000L; // sequence ID: df_ctl : seqence count
4556 dataHDR->ox_rx_id = 0L; // clear; fix-up dataHDR fields later
4557 dataHDR->ro = 0x0L; // relative offset (n/a)
4558
4559 // Now setup the SEST entry
4560 pIWE = &fcChip->SEST->u[ *fcExchangeIndex ].IWE;
4561
4562 // fill out the IWE:
4563
4564 // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
4565 pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
4566
4567
4568 // from login parameters with other port, what's the largest frame
4569 // we can send?
4570 if( pLoggedInPort == NULL)
4571 {
4572 ulStatus = INVALID_ARGS; // failed! give up
4573 break;
4574 }
4575 if( pLoggedInPort->rx_data_size >= 2048)
4576 fl = 0x00020000; // 2048 code (only support 1024!)
4577 else if( pLoggedInPort->rx_data_size >= 1024)
4578 fl = 0x00020000; // 1024 code
4579 else if( pLoggedInPort->rx_data_size >= 512)
4580 fl = 0x00010000; // 512 code
4581 else
4582 fl = 0; // 128 bytes -- should never happen
4583
4584
4585 pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
4586 pIWE->Hdr_Addr = fcChip->SEST->base +
4587 ((unsigned long)&fcChip->SEST->DataHDR[*fcExchangeIndex] -
4588 (unsigned long)fcChip->SEST);
4589
4590 pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
4591 pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4592
4593 memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0,
4594 sizeof( FCP_STATUS_RESPONSE) ); // clear out previous status
4595
4596 pIWE->RSP_Addr = fcChip->SEST->base +
4597 ((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] -
4598 (unsigned long)fcChip->SEST);
4599
4600 // Do we need local or extended gather list?
4601 // depends on size - we can handle 3 len/addr pairs
4602 // locally.
4603
4604 fcp_dl = build_SEST_sgList(
4605 cpqfcHBAdata->PciDev,
4606 &pIWE->GLen1,
4607 Cmnd, // S/G list
4608 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4609 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4610
4611 if( !fcp_dl ) // error building S/G list?
4612 {
4613 ulStatus = MEMPOOL_FAIL;
4614 break; // give up
4615 }
4616
4617 // Now that we know total data length in
4618 // the passed S/G buffer, set FCP CMND frame
4619 build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4620
4621
4622
4623 if( sgPairs > 3 ) // need extended s/g list
4624 pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
4625 else // local data pointers (in SEST)
4626 pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
4627
4628 // ULONG 5
4629 pIWE->Link = 0x0000ffffL; // Buff_Index | Link
4630
4631 pIWE->RX_ID = 0x0L; // DWord 6: RX_ID set by target XFER_RDY
4632
4633 // DWord 7
4634 pIWE->Data_Len = 0L; // TL enters rcv'd XFER_RDY BURST_LEN
4635 pIWE->Exp_RO = 0L; // DWord 8
4636 // DWord 9
4637 pIWE->Exp_Byte_Cnt = fcp_dl; // sum of gather buffers
4638 }
4639 break;
4640
4641
4642
4643
4644
4645 case SCSI_IRE: // TachLite Initiator Read Entry
4646
4647 if( Cmnd->timeout != 0)
4648 {
4649// printk("Cmnd->timeout %d\n", Cmnd->timeout);
4650 // per Linux Scsi
4651 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = Cmnd->timeout;
4652 }
4653 else // use our best guess, based on FC & device
4654 {
4655
4656 if( Cmnd->SCp.Message == 1 ) // Tape device? (from INQUIRY)
4657 {
4658 // turn off our timeouts (for now...)
4659 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 0xFFFFFFFF;
4660 }
4661 else
4662 {
4663 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
4664 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // per SCSI req.
4665 }
4666 }
4667
4668
4669 // first, build FCP_CMND
4670
4671
4672 *pIRB_flags = 0; // clear IRB flags
4673 IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
4674 // NOTE: unlike FC LinkService login frames,
4675 // normal SCSI commands are sent "open loop"
4676 IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
4677 SfsLen = *pIRB_flags;
4678
4679 SfsLen <<= 24; // shift flags to MSB
4680 SfsLen += 64L; // add len to LSB (header & CMND payload)
4681
4682 CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
4683
4684 // TYPE[31-24] 8 for FCP SCSI
4685 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4686 // valid RO
4687 CMDfchs->f_ctl = 0x08210008L;
4688 CMDfchs->seq_cnt = 0x0L;
4689 // x_ID & data direction bit set later
4690 CMDfchs->ox_rx_id = 0xFFFF; // clear
4691 CMDfchs->ro = 0x0L; // relative offset (n/a)
4692
4693
4694
4695 // Now setup the SEST entry
4696 pIRE = &fcChip->SEST->u[ *fcExchangeIndex ].IRE;
4697
4698 // fill out the IRE:
4699 // VALid entry:Dir outbound:enable CM:enal INT:
4700 pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
4701
4702 pIRE->reserved = 0L;
4703 pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
4704 pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4705
4706 pIRE->RSP_Addr = fcChip->SEST->base +
4707 ((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] -
4708 (unsigned long)fcChip->SEST);
4709
4710 // Do we need local or extended gather list?
4711 // depends on size - we can handle 3 len/addr pairs
4712 // locally.
4713
4714 fcp_dl = build_SEST_sgList(
4715 cpqfcHBAdata->PciDev,
4716 &pIRE->SLen1,
4717 Cmnd, // SCSI command Data desc. with S/G list
4718 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4719 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4720
4721
4722 if( !fcp_dl ) // error building S/G list?
4723 {
4724 // It is permissible to have a ZERO LENGTH Read command.
4725 // If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
4726 // to 0 and continue.
4727 if( Cmnd->request_bufflen == 0 )
4728 {
4729 fcp_dl = 0; // no FC DATA frames expected
4730
4731 }
4732 else
4733 {
4734 ulStatus = MEMPOOL_FAIL;
4735 break; // give up
4736 }
4737 }
4738
4739 // now that we know the S/G length, build CMND payload
4740 build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4741
4742
4743 if( sgPairs > 3 ) // need extended s/g list
4744 pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
4745 else
4746 pIRE->Buff_Off = 0x80000000; // local data, no offset
4747
4748 pIRE->Buff_Index = 0x0L; // DWord 5: Buff_Index | Reserved
4749
4750 pIRE->Exp_RO = 0x0L; // DWord 6: Expected Rel. Offset
4751
4752 pIRE->Byte_Count = 0; // DWord 7: filled in by TL on err
4753 pIRE->reserved_ = 0; // DWord 8: reserved
4754 // NOTE: 0 length READ is OK.
4755 pIRE->Exp_Byte_Cnt = fcp_dl;// DWord 9: sum of scatter buffers
4756
4757 break;
4758
4759
4760
4761
4762 // Fibre Channel SCSI 'responder' sequences...
4763 // (originator means 'target' in FCP-SCSI)
4764 case SCSI_TWE: // TachLite Target Write Entry
4765
4766 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
4767
4768 // first, build FCP_CMND
4769
4770 *pIRB_flags = 0; // clear IRB flags
4771 IRB_flags.SFA = 1; // send SFS (XFER_RDY)
4772 SfsLen = *pIRB_flags;
4773
4774 SfsLen <<= 24; // shift flags to MSB
4775 SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
4776
4777 CMDfchs->d_id |= (0x05000000L); // R_CTL = 5 for XFER_RDY
4778
4779 // TYPE[31-24] 8 for FCP SCSI
4780 // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
4781 // valid RO
4782 CMDfchs->f_ctl = 0x08810008L;
4783 CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
4784 // use originator (other port's) OX_ID
4785 CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // we want upper 16 bits
4786 CMDfchs->ro = 0x0L; // relative offset (n/a)
4787
4788 // now, fill out FCP-RSP header
4789 // (use buffer inside SEST object)
4790
4791 rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
4792 rspHDR->reserved = 0L; // must clear
4793 rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
4794 rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
4795 rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4796 // TYPE[31-24] 8 for FCP SCSI
4797 // f_ctl[23:0] responder|last seq| xfer S.I.
4798 rspHDR->f_ctl = 0x08910000L;
4799 rspHDR->seq_cnt = 0x03000000; // sequence ID
4800 rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
4801 rspHDR->ro = 0x0L; // relative offset (n/a)
4802
4803
4804 // Now setup the SEST entry
4805
4806 pTWE = &fcChip->SEST->u[ *fcExchangeIndex ].TWE;
4807
4808 // fill out the TWE:
4809
4810 // VALid entry:Dir outbound:enable CM:enal INT:
4811 pTWE->Seq_Accum = 0xC4000000L; // upper word flags
4812 pTWE->reserved = 0L;
4813 pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
4814 pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4815
4816
4817 // Do we need local or extended gather list?
4818 // depends on size - we can handle 3 len/addr pairs
4819 // locally.
4820
4821 fcp_dl = build_SEST_sgList(
4822 cpqfcHBAdata->PciDev,
4823 &pTWE->SLen1,
4824 Cmnd, // S/G list
4825 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4826 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4827
4828
4829 if( !fcp_dl ) // error building S/G list?
4830 {
4831 ulStatus = MEMPOOL_FAIL;
4832 break; // give up
4833 }
4834
4835 // now that we know the S/G length, build CMND payload
4836 build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4837
4838
4839 if( sgPairs > 3 ) // need extended s/g list
4840 pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
4841 else
4842 pTWE->Buff_Off = 0x80000000; // local data, no offset
4843
4844 pTWE->Buff_Index = 0; // Buff_Index | Link
4845 pTWE->Exp_RO = 0;
4846 pTWE->Byte_Count = 0; // filled in by TL on err
4847 pTWE->reserved_ = 0;
4848 pTWE->Exp_Byte_Cnt = fcp_dl;// sum of scatter buffers
4849
4850 break;
4851
4852
4853
4854
4855
4856
4857 case SCSI_TRE: // TachLite Target Read Entry
4858
4859 // It doesn't make much sense for us to "time-out" a READ,
4860 // but we'll use it for design consistency and internal error recovery.
4861 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
4862
4863 // I/O request block settings...
4864 *pIRB_flags = 0; // clear IRB flags
4865 // check PRLI (process login) info
4866 // to see if Initiator Requires XFER_RDY
4867 // if not, don't send one!
4868 // { PRLI check...}
4869 IRB_flags.SFA = 0; // don't send XFER_RDY - start data
4870 SfsLen = *pIRB_flags;
4871
4872 SfsLen <<= 24; // shift flags to MSB
4873 SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
4874
4875
4876
4877 // now, fill out FCP-DATA header
4878 // (use buffer inside SEST object)
4879 dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
4880
4881 dataHDR->reserved = 0L; // must clear
4882 dataHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
4883 dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
4884 dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4885
4886
4887 // TYPE[31-24] 8 for FCP SCSI
4888 // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
4889 // valid RO
4890 dataHDR->f_ctl = 0x08810008L;
4891 dataHDR->seq_cnt = 0x01000000; // sequence ID (no XRDY)
4892 dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
4893 dataHDR->ro = 0x0L; // relative offset (n/a)
4894
4895 // now, fill out FCP-RSP header
4896 // (use buffer inside SEST object)
4897 rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
4898
4899 rspHDR->reserved = 0L; // must clear
4900 rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
4901 rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
4902 rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4903 // TYPE[31-24] 8 for FCP SCSI
4904 // f_ctl[23:0] responder|last seq| xfer S.I.
4905 rspHDR->f_ctl = 0x08910000L;
4906 rspHDR->seq_cnt = 0x02000000; // sequence ID: df_ctl: sequence count
4907
4908 rspHDR->ro = 0x0L; // relative offset (n/a)
4909
4910
4911 // Now setup the SEST entry
4912 pTRE = &fcChip->SEST->u[ *fcExchangeIndex ].TRE;
4913
4914
4915 // VALid entry:Dir outbound:enable CM:enal INT:
4916 pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
4917 pTRE->Hdr_Addr = // bus address of dataHDR;
4918 fcChip->SEST->base +
4919 ((unsigned long)&fcChip->SEST->DataHDR[ *fcExchangeIndex ] -
4920 (unsigned long)fcChip->SEST);
4921
4922 pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
4923 pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4924 pTRE->RSP_Addr = // bus address of rspHDR
4925 fcChip->SEST->base +
4926 ((unsigned long)&fcChip->SEST->RspHDR[ *fcExchangeIndex ] -
4927 (unsigned long)fcChip->SEST);
4928
4929 // Do we need local or extended gather list?
4930 // depends on size - we can handle 3 len/addr pairs
4931 // locally.
4932
4933 fcp_dl = build_SEST_sgList(
4934 cpqfcHBAdata->PciDev,
4935 &pTRE->GLen1,
4936 Cmnd, // S/G list
4937 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4938 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4939
4940
4941 if( !fcp_dl ) // error building S/G list?
4942 {
4943 ulStatus = MEMPOOL_FAIL;
4944 break; // give up
4945 }
4946
4947 // no payload or command to build -- READ doesn't need XRDY
4948
4949
4950 if( sgPairs > 3 ) // need extended s/g list
4951 pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
4952 else // local data pointers (in SEST)
4953 pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
4954
4955 // ULONG 5
4956 pTRE->Buff_Index = 0L; // Buff_Index | reserved
4957 pTRE->reserved = 0x0L; // DWord 6
4958
4959 // DWord 7: NOTE: zero length will
4960 // hang TachLite!
4961 pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
4962
4963 pTRE->reserved_ = 0L; // DWord 8
4964 pTRE->reserved__ = 0L; // DWord 9
4965
4966 break;
4967
4968
4969
4970
4971
4972
4973
4974 case FCP_RESPONSE:
4975 // Target response frame: this sequence uses an OX/RX ID
4976 // pair from a completed SEST exchange. We built most
4977 // of the response frame when we created the TWE/TRE.
4978
4979 *pIRB_flags = 0; // clear IRB flags
4980 IRB_flags.SFA = 1; // send SFS (RSP)
4981 SfsLen = *pIRB_flags;
4982
4983 SfsLen <<= 24; // shift flags to MSB
4984 SfsLen += sizeof(TachFCHDR_RSP);// add SFS len (header & RSP payload)
4985
4986
4987 Exchanges->fcExchange[ *fcExchangeIndex].type =
4988 FCP_RESPONSE; // change Exchange type to "response" phase
4989
4990 // take advantage of prior knowledge of OX/RX_ID pair from
4991 // previous XFER outbound frame (still in fchs of exchange)
4992 fcChip->SEST->RspHDR[ *fcExchangeIndex ].ox_rx_id =
4993 CMDfchs->ox_rx_id;
4994
4995 // Check the status of the DATA phase of the exchange so we can report
4996 // status to the initiator
4997 buildFCPstatus( fcChip, *fcExchangeIndex); // set RSP payload fields
4998
4999 memcpy(
5000 CMDfchs, // re-use same XFER fchs for Response frame
5001 &fcChip->SEST->RspHDR[ *fcExchangeIndex ],
5002 sizeof( TachFCHDR_RSP ));
5003
5004
5005 break;
5006
5007 default:
5008 printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type,type);
5009 break;
5010
5011 }
5012
5013
5014
5015 if( !ulStatus) // no errors above?
5016 {
5017 // FCHS is built; now build IRB
5018
5019 // link the just built FCHS (the "command") to the IRB entry
5020 // for this Exchange.
5021 pIRB = &Exchanges->fcExchange[ *fcExchangeIndex].IRB;
5022
5023 // len & flags according to command type above
5024 pIRB->Req_A_SFS_Len = SfsLen; // includes IRB flags & len
5025 pIRB->Req_A_SFS_Addr = // TL needs physical addr of frame to send
5026 fcChip->exch_dma_handle + (unsigned long)CMDfchs -
5027 (unsigned long)Exchanges;
5028
5029 pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
5030
5031 // Exchange is complete except for "fix-up" fields to be set
5032 // at Tachyon Queuing time:
5033 // IRB->Req_A_Trans_ID (OX_ID/ RX_ID):
5034 // for SEST entry, lower bits correspond to actual FC Exchange ID
5035 // fchs->OX_ID or RX_ID
5036 }
5037 else
5038 {
5039#ifdef DBG
5040 printk( "FC Error: SEST build Pool Allocation failed\n");
5041#endif
5042 // return resources...
5043 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, *fcExchangeIndex); // SEST build failed
5044 }
5045 }
5046 else // no Exchanges available
5047 {
5048 ulStatus = SEST_FULL;
5049 printk( "FC Error: no fcExchanges available\n");
5050 }
5051 return ulStatus;
5052}
5053
5054
5055
5056
5057
5058
5059// set RSP payload fields
5060static void buildFCPstatus( PTACHYON fcChip, ULONG ExchangeID)
5061{
5062 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5063 FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID]; // shorthand
5064 PFCP_STATUS_RESPONSE pFcpStatus;
5065
5066 memset( &fcChip->SEST->RspHDR[ ExchangeID ].pl, 0,
5067 sizeof( FCP_STATUS_RESPONSE) );
5068 if( pExchange->status ) // something wrong?
5069 {
5070 pFcpStatus = (PFCP_STATUS_RESPONSE) // cast RSP buffer for this xchng
5071 &fcChip->SEST->RspHDR[ ExchangeID ].pl;
5072 if( pExchange->status & COUNT_ERROR )
5073 {
5074
5075 // set FCP response len valid (so we can report count error)
5076 pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
5077 pFcpStatus->fcp_rsp_len = 0x04000000; // 4 byte len (BIG Endian)
5078
5079 pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
5080 }
5081 }
5082}
5083
5084
5085static dma_addr_t
5086cpqfc_pci_map_sg_page(
5087 struct pci_dev *pcidev,
5088 ULONG *hw_paddr, // where to put phys addr for HW use
5089 void *sgp_vaddr, // the virtual address of the sg page
5090 dma_addr_t *umap_paddr, // where to put phys addr for unmap
5091 unsigned int *maplen, // where to store sg entry length
5092 int PairCount) // number of sg pairs used in the page.
5093{
5094 unsigned long aligned_addr = (unsigned long) sgp_vaddr;
5095
5096 *maplen = PairCount * 8;
5097 aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
5098 aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
5099
5100 *umap_paddr = pci_map_single(pcidev, (void *) aligned_addr,
5101 *maplen, PCI_DMA_TODEVICE);
5102 *hw_paddr = (ULONG) *umap_paddr;
5103
5104# if BITS_PER_LONG > 32
5105 if( *umap_paddr >>32 ) {
5106 printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n",
5107 (void*)umap_paddr);
5108 return 0;
5109 }
5110# endif
5111 return *umap_paddr;
5112}
5113
5114static void
5115cpqfc_undo_SEST_mappings(struct pci_dev *pcidev,
5116 unsigned long contigaddr, int len, int dir,
5117 struct scatterlist *sgl, int use_sg,
5118 PSGPAGES *sgPages_head,
5119 int allocated_pages)
5120{
5121 PSGPAGES i, next;
5122
5123 if (contigaddr != (unsigned long) NULL)
5124 pci_unmap_single(pcidev, contigaddr, len, dir);
5125
5126 if (sgl != NULL)
5127 pci_unmap_sg(pcidev, sgl, use_sg, dir);
5128
5129 for (i=*sgPages_head; i != NULL ;i = next)
5130 {
5131 pci_unmap_single(pcidev, i->busaddr, i->maplen,
5132 PCI_DMA_TODEVICE);
5133 i->busaddr = (dma_addr_t) NULL;
5134 i->maplen = 0L;
5135 next = i->next;
5136 kfree(i);
5137 }
5138 *sgPages_head = NULL;
5139}
5140
5141// This routine builds scatter/gather lists into SEST entries
5142// INPUTS:
5143// SESTalPair - SEST address @DWordA "Local Buffer Length"
5144// sgList - Scatter/Gather linked list of Len/Address data buffers
5145// OUTPUT:
5146// sgPairs - number of valid address/length pairs
5147// Remarks:
5148// The SEST data buffer pointers only depend on number of
5149// length/ address pairs, NOT on the type (IWE, TRE,...)
5150// Up to 3 pairs can be referenced in the SEST - more than 3
5151// require this Extended S/G list page. The page holds 4, 8, 16...
5152// len/addr pairs, per Scatter/Gather List Page Length Reg.
5153// TachLite allows pages to be linked to any depth.
5154
5155//#define DBG_SEST_SGLIST 1 // for printing out S/G pairs with Ext. pages
5156
5157static int ap_hi_water = TL_DANGER_SGPAGES;
5158
5159static ULONG build_SEST_sgList(
5160 struct pci_dev *pcidev,
5161 ULONG *SESTalPairStart, // the 3 len/address buffers in SEST
5162 Scsi_Cmnd *Cmnd,
5163 ULONG *sgPairs,
5164 PSGPAGES *sgPages_head) // link list of TL Ext. S/G pages from O/S Pool
5165
5166{
5167 ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations
5168 ULONG* alPair = SESTalPairStart;
5169 ULONG* ext_sg_page_phys_addr_place = NULL;
5170 int PairCount;
5171 unsigned long ulBuff, contigaddr;
5172 ULONG total_data_len=0; // (in bytes)
5173 ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
5174 ULONG thisMappingLen;
5175 struct scatterlist *sgl = NULL; // S/G list (Linux format)
5176 int sg_count, totalsgs;
5177 dma_addr_t busaddr;
5178 unsigned long thislen, offset;
5179 PSGPAGES *sgpage = sgPages_head;
5180 PSGPAGES prev_page = NULL;
5181
5182# define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
5183 contigaddr = (unsigned long) NULL;
5184
5185 if( !Cmnd->use_sg ) // no S/G list?
5186 {
5187 if (bytes_to_go <= TL_MAX_SG_ELEM_LEN)
5188 {
5189 *sgPairs = 1; // use "local" S/G pair in SEST entry
5190 // (for now, ignore address bits above #31)
5191
5192 *alPair++ = bytes_to_go; // bits 18-0, length
5193
5194 if (bytes_to_go != 0) {
5195 contigaddr = ulBuff = pci_map_single(pcidev,
5196 Cmnd->request_buffer,
5197 Cmnd->request_bufflen,
5198 Cmnd->sc_data_direction);
5199 // printk("ms %p ", ulBuff);
5200 }
5201 else {
5202 // No data transfer, (e.g.: Test Unit Ready)
5203 // printk("btg=0 ");
5204 *sgPairs = 0;
5205 memset(alPair, 0, sizeof(*alPair));
5206 return 0;
5207 }
5208
5209# if BITS_PER_LONG > 32
5210 if( ulBuff >>32 ) {
5211 printk("FATAL! Tachyon DMA address %p "
5212 "exceeds 32 bits\n", (void*)ulBuff );
5213 return 0;
5214 }
5215# endif
5216 *alPair = (ULONG)ulBuff;
5217 return bytes_to_go;
5218 }
5219 else // We have a single large (too big) contiguous buffer.
5220 { // We will have to break it up. We'll use the scatter
5221 // gather code way below, but use contigaddr instead
5222 // of sg_dma_addr(). (this is a very rare case).
5223
5224 unsigned long btg;
5225 contigaddr = pci_map_single(pcidev, Cmnd->request_buffer,
5226 Cmnd->request_bufflen,
5227 Cmnd->sc_data_direction);
5228
5229 // printk("contigaddr = %p, len = %d\n",
5230 // (void *) contigaddr, bytes_to_go);
5231 totalsgs = 0;
5232 for (btg = bytes_to_go; btg > 0; ) {
5233 btg -= ( btg > TL_MAX_SG_ELEM_LEN ?
5234 TL_MAX_SG_ELEM_LEN : btg );
5235 totalsgs++;
5236 }
5237 sgl = NULL;
5238 *sgPairs = totalsgs;
5239 }
5240 }
5241 else // we do have a scatter gather list
5242 {
5243 // [TBD - update for Linux to support > 32 bits addressing]
5244 // since the format for local & extended S/G lists is different,
5245 // check if S/G pairs exceeds 3.
5246 // *sgPairs = Cmnd->use_sg; Nope, that's wrong.
5247
5248 sgl = (struct scatterlist*)Cmnd->request_buffer;
5249 sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg,
5250 Cmnd->sc_data_direction);
5251 if( sg_count <= 3 ) {
5252
5253 // we need to be careful here that no individual mapping
5254 // is too large, and if any is, that breaking it up
5255 // doesn't push us over 3 sgs, or, if it does, that we
5256 // handle that case. Tachyon can take 0x7FFFF bits for length,
5257 // but sg structure uses "unsigned int", on the face of it,
5258 // up to 0xFFFFFFFF or even more.
5259
5260 int i;
5261 unsigned long thislen;
5262
5263 totalsgs = 0;
5264 for (i=0;i<sg_count;i++) {
5265 thislen = sg_dma_len(&sgl[i]);
5266 while (thislen >= TL_MAX_SG_ELEM_LEN) {
5267 totalsgs++;
5268 thislen -= TL_MAX_SG_ELEM_LEN;
5269 }
5270 if (thislen > 0) totalsgs++;
5271 }
5272 *sgPairs = totalsgs;
5273 } else totalsgs = 999; // as a first estimate, definitely >3,
5274
5275 // if (totalsgs != sg_count)
5276 // printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
5277 }
5278
5279 if( totalsgs <= 3 ) // can (must) use "local" SEST list
5280 {
5281 while( bytes_to_go)
5282 {
5283 offset = 0L;
5284
5285 if ( WE_HAVE_SG_LIST )
5286 thisMappingLen = sg_dma_len(sgl);
5287 else // or contiguous buffer?
5288 thisMappingLen = bytes_to_go;
5289
5290 while (thisMappingLen > 0)
5291 {
5292 thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ?
5293 TL_MAX_SG_ELEM_LEN : thisMappingLen;
5294 bytes_to_go = bytes_to_go - thislen;
5295
5296 // we have L/A pair; L = thislen, A = physicalAddress
5297 // load into SEST...
5298
5299 total_data_len += thislen;
5300 *alPair = thislen; // bits 18-0, length
5301
5302 alPair++;
5303
5304 if ( WE_HAVE_SG_LIST )
5305 ulBuff = sg_dma_address(sgl) + offset;
5306 else
5307 ulBuff = contigaddr + offset;
5308
5309 offset += thislen;
5310
5311# if BITS_PER_LONG > 32
5312 if( ulBuff >>32 ) {
5313 printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n",
5314 (void*)ulBuff );
5315 printk("%s = %p, offset = %ld\n",
5316 WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
5317 WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
5318 offset);
5319 return 0;
5320 }
5321# endif
5322 *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
5323 thisMappingLen -= thislen;
5324 }
5325
5326 if ( WE_HAVE_SG_LIST ) ++sgl; // next S/G pair
5327 else if (bytes_to_go != 0) printk("BTG not zero!\n");
5328
5329# ifdef DBG_SEST_SGLIST
5330 printk("L=%d ", thisMappingLen);
5331 printk("btg=%d ", bytes_to_go);
5332# endif
5333
5334 }
5335 // printk("i:%d\n", *sgPairs);
5336 }
5337 else // more than 3 pairs requires Extended S/G page (Pool Allocation)
5338 {
5339 // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
5340 for( i=2; i<6; i++)
5341 alPair[i] = 0;
5342
5343 PairCount = TL_EXT_SG_PAGE_COUNT; // forces initial page allocation
5344 totalsgs = 0;
5345 while( bytes_to_go )
5346 {
5347 // Per SEST format, we can support 524287 byte lengths per
5348 // S/G pair. Typical user buffers are 4k, and very rarely
5349 // exceed 12k due to fragmentation of physical memory pages.
5350 // However, on certain O/S system (not "user") buffers (on platforms
5351 // with huge memories), it's possible to exceed this
5352 // length in a single S/G address/len mapping, so we have to handle
5353 // that.
5354
5355 offset = 0L;
5356 if ( WE_HAVE_SG_LIST )
5357 thisMappingLen = sg_dma_len(sgl);
5358 else
5359 thisMappingLen = bytes_to_go;
5360
5361 while (thisMappingLen > 0)
5362 {
5363 thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ?
5364 TL_MAX_SG_ELEM_LEN : thisMappingLen;
5365 // printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
5366
5367 // should we load into "this" extended S/G page, or allocate
5368 // new page?
5369
5370 if( PairCount >= TL_EXT_SG_PAGE_COUNT )
5371 {
5372 // Now, we have to map the previous page, (triggering buffer bounce)
5373 // The first time thru the loop, there won't be a previous page.
5374 if (prev_page != NULL) // is there a prev page?
5375 {
5376 // this code is normally kind of hard to trigger,
5377 // you have to use up more than 256 scatter gather
5378 // elements to get here. Cranking down TL_MAX_SG_ELEM_LEN
5379 // to an absurdly low value (128 bytes or so) to artificially
5380 // break i/o's into a zillion pieces is how I tested it.
5381 busaddr = cpqfc_pci_map_sg_page(pcidev,
5382 ext_sg_page_phys_addr_place,
5383 prev_page->page,
5384 &prev_page->busaddr,
5385 &prev_page->maplen,
5386 PairCount);
5387 }
5388 // Allocate the TL Extended S/G list page. We have
5389 // to allocate twice what we want to ensure required TL alignment
5390 // (Tachlite TL/TS User Man. Rev 6.0, p 168)
5391 // We store the original allocated PVOID so we can free later
5392 *sgpage = kmalloc( sizeof(SGPAGES), GFP_ATOMIC);
5393 if ( ! *sgpage )
5394 {
5395 printk("cpqfc: Allocation failed @ %d S/G page allocations\n",
5396 AllocatedPages);
5397 total_data_len = 0; // failure!! Ext. S/G is All-or-none affair
5398
5399 // unmap the previous mappings, if any.
5400
5401 cpqfc_undo_SEST_mappings(pcidev, contigaddr,
5402 Cmnd->request_bufflen,
5403 Cmnd->sc_data_direction,
5404 sgl, Cmnd->use_sg, sgPages_head, AllocatedPages+1);
5405
5406 // FIXME: testing shows that if we get here,
5407 // it's bad news. (this has been this way for a long
5408 // time though, AFAIK. Not that that excuses it.)
5409
5410 return 0; // give up (and probably hang the system)
5411 }
5412 // clear out memory we just allocated
5413 memset( (*sgpage)->page,0,TL_EXT_SG_PAGE_BYTELEN*2);
5414 (*sgpage)->next = NULL;
5415 (*sgpage)->busaddr = (dma_addr_t) NULL;
5416 (*sgpage)->maplen = 0L;
5417
5418 // align the memory - TL requires sizeof() Ext. S/G page alignment.
5419 // We doubled the actual required size so we could mask off LSBs
5420 // to get desired offset
5421
5422 ulBuff = (unsigned long) (*sgpage)->page;
5423 ulBuff += TL_EXT_SG_PAGE_BYTELEN;
5424 ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
5425
5426 // set pointer, in SEST if first Ext. S/G page, or in last pair
5427 // of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just
5428 // load lower 32 bits)
5429 // NOTE: the Len field must be '0' if this is the first Ext. S/G
5430 // pointer in SEST, and not 0 otherwise (we know thislen != 0).
5431
5432 *alPair = (alPair != SESTalPairStart) ? thislen : 0;
5433
5434# ifdef DBG_SEST_SGLIST
5435 printk("PairCount %d @%p even %Xh, ",
5436 PairCount, alPair, *alPair);
5437# endif
5438
5439 // Save the place where we need to store the physical
5440 // address of this scatter gather page which we get when we map it
5441 // (and mapping we can do only after we fill it in.)
5442 alPair++; // next DWORD, will contain phys addr of the ext page
5443 ext_sg_page_phys_addr_place = alPair;
5444
5445 // Now, set alPair = the virtual addr of the (Extended) S/G page
5446 // which will accept the Len/ PhysicalAddress pairs
5447 alPair = (ULONG *) ulBuff;
5448
5449 AllocatedPages++;
5450 if (AllocatedPages >= ap_hi_water)
5451 {
5452 // This message should rarely, if ever, come out.
5453 // Previously (cpqfc version <= 2.0.5) the driver would
5454 // just puke if more than 4 SG pages were used, and nobody
5455 // ever complained about that. This only comes out if
5456 // more than 8 pages are used.
5457
5458 printk(KERN_WARNING
5459 "cpqfc: Possible danger. %d scatter gather pages used.\n"
5460 "cpqfc: detected seemingly extreme memory "
5461 "fragmentation or huge data transfers.\n",
5462 AllocatedPages);
5463 ap_hi_water = AllocatedPages+1;
5464 }
5465
5466 PairCount = 1; // starting new Ext. S/G page
5467 prev_page = (*sgpage); // remember this page, for next time thru
5468 sgpage = &((*sgpage)->next);
5469 } // end of new TL Ext. S/G page allocation
5470
5471 *alPair = thislen; // bits 18-0, length (range check above)
5472
5473# ifdef DBG_SEST_SGLIST
5474 printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
5475# endif
5476
5477 alPair++; // next DWORD, physical address
5478
5479 if ( WE_HAVE_SG_LIST )
5480 ulBuff = sg_dma_address(sgl) + offset;
5481 else
5482 ulBuff = contigaddr + offset;
5483 offset += thislen;
5484
5485# if BITS_PER_LONG > 32
5486 if( ulBuff >>32 )
5487 {
5488 printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void*)ulBuff );
5489 printk("%s = %p, offset = %ld\n",
5490 WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
5491 WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
5492 offset);
5493 return 0;
5494 }
5495# endif
5496
5497 *alPair = (ULONG) ulBuff; // lower 32 bits (31-0)
5498
5499# ifdef DBG_SEST_SGLIST
5500 printk("odd %Xh\n", *alPair);
5501# endif
5502 alPair++; // next DWORD, next address/length pair
5503
5504 PairCount++; // next Length/Address pair
5505
5506 // if (PairCount > pc_hi_water)
5507 // {
5508 // printk("pc hi = %d ", PairCount);
5509 // pc_hi_water = PairCount;
5510 // }
5511 bytes_to_go -= thislen;
5512 total_data_len += thislen;
5513 thisMappingLen -= thislen;
5514 totalsgs++;
5515 } // while (thisMappingLen > 0)
5516 if ( WE_HAVE_SG_LIST ) sgl++; // next S/G pair
5517 } // while (bytes_to_go)
5518
5519 // printk("Totalsgs=%d\n", totalsgs);
5520 *sgPairs = totalsgs;
5521
5522 // PCI map (and bounce) the last (and usually only) extended SG page
5523 busaddr = cpqfc_pci_map_sg_page(pcidev,
5524 ext_sg_page_phys_addr_place,
5525 prev_page->page,
5526 &prev_page->busaddr,
5527 &prev_page->maplen,
5528 PairCount);
5529 }
5530 return total_data_len;
5531}
5532
5533
5534
5535// The Tachlite SEST table is referenced to OX_ID (or RX_ID). To optimize
5536// performance and debuggability, we index the Exchange structure to FC X_ID
5537// This enables us to build exchanges for later en-queing to Tachyon,
5538// provided we have an open X_ID slot. At Tachyon queing time, we only
5539// need an ERQ slot; then "fix-up" references in the
5540// IRB, FCHS, etc. as needed.
5541// RETURNS:
5542// 0 if successful
5543// non-zero on error
5544//sstartex
5545ULONG cpqfcTSStartExchange(
5546 CPQFCHBA *cpqfcHBAdata,
5547 LONG ExchangeID )
5548{
5549 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
5550 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5551 FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ ExchangeID ]; // shorthand
5552 USHORT producer, consumer;
5553 ULONG ulStatus=0;
5554 short int ErqIndex;
5555 BOOLEAN CompleteExchange = FALSE; // e.g. ACC replies are complete
5556 BOOLEAN SestType=FALSE;
5557 ULONG InboundData=0;
5558
5559 // We will manipulate Tachlite chip registers here to successfully
5560 // start exchanges.
5561
5562 // Check that link is not down -- we can't start an exchange on a
5563 // down link!
5564
5565 if( fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
5566 {
5567printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n",
5568 fcChip->Registers.FMstatus.value & 0xFF,
5569 ExchangeID,
5570 pExchange->type,
5571 pExchange->fchs.d_id);
5572
5573 if( ExchangeID >= TACH_SEST_LEN ) // Link Service Outbound frame?
5574 {
5575 // Our most popular LinkService commands are port discovery types
5576 // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
5577 // events, so it makes no sense to Que them. However, ABTS should
5578 // be queued, since exchange sequences are likely destroyed by
5579 // Link Down events, and we want to notify other ports of broken
5580 // sequences by aborting the corresponding exchanges.
5581 if( pExchange->type != BLS_ABTS )
5582 {
5583 ulStatus = LNKDWN_OSLS;
5584 goto Done;
5585 // don't Que most LinkServ exchanges on LINK DOWN
5586 }
5587 }
5588
5589 printk("fcStartExchange: Que x_ID %Xh, type %Xh\n",
5590 ExchangeID, pExchange->type);
5591 pExchange->status |= EXCHANGE_QUEUED;
5592 ulStatus = EXCHANGE_QUEUED;
5593 goto Done;
5594 }
5595
5596 // Make sure ERQ has available space.
5597
5598 producer = (USHORT)fcChip->ERQ->producerIndex; // copies for logical arith.
5599 consumer = (USHORT)fcChip->ERQ->consumerIndex;
5600 producer++; // We are testing for full que by incrementing
5601
5602 if( producer >= ERQ_LEN ) // rollover condition?
5603 producer = 0;
5604 if( consumer != producer ) // ERQ not full?
5605 {
5606 // ****************** Need Atomic access to chip registers!!********
5607
5608 // remember ERQ PI for copying IRB
5609 ErqIndex = (USHORT)fcChip->ERQ->producerIndex;
5610 fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
5611 // we have an ERQ slot! If SCSI command, need SEST slot
5612 // otherwise we are done.
5613
5614 // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
5615 // set according to direction of data to/from Tachyon for SEST assists.
5616 // For consistency, enforce this rule for Link Service (non-SEST)
5617 // exchanges as well.
5618
5619 // fix-up the X_ID field in IRB
5620 pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
5621
5622 // fix-up the X_ID field in fchs -- depends on Originator or Responder,
5623 // outgoing or incoming data?
5624 switch( pExchange->type )
5625 {
5626 // ORIGINATOR types... we're setting our OX_ID and
5627 // defaulting the responder's RX_ID to 0xFFFF
5628
5629 case SCSI_IRE:
5630 // Requirement: set MSB of x_ID for Incoming TL data
5631 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5632 InboundData = 0x8000;
5633
5634 case SCSI_IWE:
5635 SestType = TRUE;
5636 pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
5637 pExchange->fchs.ox_rx_id <<= 16; // MSW shift
5638 pExchange->fchs.ox_rx_id |= 0xffff; // add default RX_ID
5639
5640 // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
5641 // (not necessary for IRE -- data buffer unused)
5642 if( pExchange->type == SCSI_IWE)
5643 {
5644 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id =
5645 pExchange->fchs.ox_rx_id;
5646
5647 }
5648
5649 break;
5650
5651
5652 case FCS_NSR: // ext. link service Name Service Request
5653 case ELS_SCR: // ext. link service State Change Registration
5654 case ELS_FDISC:// ext. link service login
5655 case ELS_FLOGI:// ext. link service login
5656 case ELS_LOGO: // FC-PH extended link service logout
5657 case BLS_NOP: // Basic link service No OPeration
5658 case ELS_PLOGI:// ext. link service login (PLOGI)
5659 case ELS_PDISC:// ext. link service login (PDISC)
5660 case ELS_PRLI: // ext. link service process login
5661
5662 pExchange->fchs.ox_rx_id = ExchangeID;
5663 pExchange->fchs.ox_rx_id <<= 16; // MSW shift
5664 pExchange->fchs.ox_rx_id |= 0xffff; // and RX_ID
5665
5666 break;
5667
5668
5669
5670
5671 // RESPONDER types... we must set our RX_ID while preserving
5672 // sender's OX_ID
5673 // outgoing (or no) data
5674 case ELS_RJT: // extended link service reject
5675 case ELS_LOGO_ACC: // FC-PH extended link service logout accept
5676 case ELS_ACC: // ext. generic link service accept
5677 case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
5678 case ELS_PRLI_ACC: // ext. link service process login accept
5679
5680 CompleteExchange = TRUE; // Reply (ACC or RJT) is end of exchange
5681 pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
5682
5683 break;
5684
5685
5686 // since we are a Responder, OX_ID should already be set by
5687 // cpqfcTSBuildExchange(). We need to -OR- in RX_ID
5688 case SCSI_TWE:
5689 SestType = TRUE;
5690 // Requirement: set MSB of x_ID for Incoming TL data
5691 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5692
5693 pExchange->fchs.ox_rx_id &= 0xFFFF0000; // clear RX_ID
5694 // Requirement: set MSB of RX_ID for Incoming TL data
5695 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5696 pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
5697 break;
5698
5699
5700 case SCSI_TRE:
5701 SestType = TRUE;
5702
5703 // there is no XRDY for SEST target read; the data
5704 // header needs to be updated. Also update the RSP
5705 // exchange IDs for the status frame, in case it is sent automatically
5706 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id |= ExchangeID;
5707 fcChip->SEST->RspHDR[ ExchangeID ].ox_rx_id =
5708 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
5709
5710 // for easier FCP response logic (works for TWE and TRE),
5711 // copy exchange IDs. (Not needed if TRE 'RSP' bit set)
5712 pExchange->fchs.ox_rx_id =
5713 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
5714
5715 break;
5716
5717
5718 case FCP_RESPONSE: // using existing OX_ID/ RX_ID pair,
5719 // start SFS FCP-RESPONSE frame
5720 // OX/RX_ID should already be set! (See "fcBuild" above)
5721 CompleteExchange = TRUE; // RSP is end of FCP-SCSI exchange
5722
5723
5724 break;
5725
5726
5727 case BLS_ABTS_RJT: // uses new RX_ID, since SEST x_ID non-existent
5728 case BLS_ABTS_ACC: // using existing OX_ID/ RX_ID pair from SEST entry
5729 CompleteExchange = TRUE; // ACC or RJT marks end of FCP-SCSI exchange
5730 case BLS_ABTS: // using existing OX_ID/ RX_ID pair from SEST entry
5731
5732
5733 break;
5734
5735
5736 default:
5737 printk("Error on fcStartExchange: undefined type %Xh(%d)\n",
5738 pExchange->type, pExchange->type);
5739 return INVALID_ARGS;
5740 }
5741
5742
5743 // X_ID fields are entered -- copy IRB to Tachyon's ERQ
5744
5745
5746 memcpy(
5747 &fcChip->ERQ->QEntry[ ErqIndex ], // dest.
5748 &pExchange->IRB,
5749 32); // fixed (hardware) length!
5750
5751 PCI_TRACEO( ExchangeID, 0xA0)
5752
5753 // ACTION! May generate INT and IMQ entry
5754 writel( fcChip->ERQ->producerIndex,
5755 fcChip->Registers.ERQproducerIndex.address);
5756
5757
5758 if( ExchangeID >= TACH_SEST_LEN ) // Link Service Outbound frame?
5759 {
5760
5761 // wait for completion! (TDB -- timeout and chip reset)
5762
5763
5764 PCI_TRACEO( ExchangeID, 0xA4)
5765
5766 enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Sem.
5767
5768 down_interruptible( cpqfcHBAdata->TYOBcomplete);
5769
5770 disable_irq( cpqfcHBAdata->HostAdapter->irq);
5771 PCI_TRACE( 0xA4)
5772
5773 // On login exchanges, BAD_ALPA (non-existent port_id) results in
5774 // FTO (Frame Time Out) on the Outbound Completion message.
5775 // If we got an FTO status, complete the exchange (free up slot)
5776 if( CompleteExchange || // flag from Reply frames
5777 pExchange->status ) // typically, can get FRAME_TO
5778 {
5779 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
5780 }
5781 }
5782
5783 else // SEST Exchange
5784 {
5785 ulStatus = 0; // ship & pray success (e.g. FCP-SCSI)
5786
5787 if( CompleteExchange ) // by Type of exchange (e.g. end-of-xchng)
5788 {
5789 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
5790 }
5791
5792 else
5793 pExchange->status &= ~EXCHANGE_QUEUED; // clear ExchangeQueued flag
5794
5795 }
5796 }
5797
5798
5799 else // ERQ 'producer' = 'consumer' and QUE is full
5800 {
5801 ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
5802 }
5803
5804Done:
5805 PCI_TRACE( 0xA0)
5806 return ulStatus;
5807}
5808
5809
5810
5811
5812
5813// Scan fcController->fcExchanges array for a usuable index (a "free"
5814// exchange).
5815// Inputs:
5816// fcChip - pointer to TachLite chip structure
5817// Return:
5818// index - exchange array element where exchange can be built
5819// -1 - exchange array is full
5820// REMARKS:
5821// Although this is a (yuk!) linear search, we presume
5822// that the system will complete exchanges about as quickly as
5823// they are submitted. A full Exchange array (and hence, max linear
5824// search time for free exchange slot) almost guarantees a Fibre problem
5825// of some sort.
5826// In the interest of making exchanges easier to debug, we want a LRU
5827// (Least Recently Used) scheme.
5828
5829
5830static LONG FindFreeExchange( PTACHYON fcChip, ULONG type )
5831{
5832 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5833 ULONG i;
5834 ULONG ulStatus=-1; // assume failure
5835
5836
5837 if( type == SCSI_IRE ||
5838 type == SCSI_TRE ||
5839 type == SCSI_IWE ||
5840 type == SCSI_TWE)
5841 {
5842 // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
5843 if( fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
5844 fcChip->fcSestExchangeLRU = 0;
5845 i = fcChip->fcSestExchangeLRU; // typically it's already free!
5846
5847 if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
5848 {
5849 ulStatus = 0; // success!
5850 }
5851
5852 else
5853 { // YUK! we need to do a linear search for free element.
5854 // Fragmentation of the fcExchange array is due to excessively
5855 // long completions or timeouts.
5856
5857 while( TRUE )
5858 {
5859 if( ++i >= TACH_SEST_LEN ) // rollover check
5860 i = 0; // beginning of SEST X_IDs
5861
5862// printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n",
5863// i, Exchanges->fcExchange[i].type);
5864
5865 if( Exchanges->fcExchange[i].type == 0 ) // "free"?
5866 {
5867 ulStatus = 0; // success!
5868 break;
5869 }
5870 if( i == fcChip->fcSestExchangeLRU ) // wrapped-around array?
5871 {
5872 printk( "SEST X_ID space full\n");
5873 break; // failed - prevent inf. loop
5874 }
5875 }
5876 }
5877 fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
5878 }
5879
5880
5881
5882 else // Link Service type - X_IDs should be from TACH_SEST_LEN
5883 // to TACH_MAX_XID
5884 {
5885 if( fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
5886 fcChip->fcLsExchangeLRU < TACH_SEST_LEN ) // (e.g. startup)
5887 fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
5888
5889 i = fcChip->fcLsExchangeLRU; // typically it's already free!
5890 if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
5891 {
5892 ulStatus = 0; // success!
5893 }
5894
5895 else
5896 { // YUK! we need to do a linear search for free element
5897 // Fragmentation of the fcExchange array is due to excessively
5898 // long completions or timeouts.
5899
5900 while( TRUE )
5901 {
5902 if( ++i >= TACH_MAX_XID ) // rollover check
5903 i = TACH_SEST_LEN;// beginning of Link Service X_IDs
5904
5905// printk( "looping for xchng ID: i=%d, type=%Xh\n",
5906// i, Exchanges->fcExchange[i].type);
5907
5908 if( Exchanges->fcExchange[i].type == 0 ) // "free"?
5909 {
5910 ulStatus = 0; // success!
5911 break;
5912 }
5913 if( i == fcChip->fcLsExchangeLRU ) // wrapped-around array?
5914 {
5915 printk( "LinkService X_ID space full\n");
5916 break; // failed - prevent inf. loop
5917 }
5918 }
5919 }
5920 fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
5921
5922 }
5923
5924 if( !ulStatus ) // success?
5925 Exchanges->fcExchange[i].type = type; // allocate it.
5926
5927 else
5928 i = -1; // error - all exchanges "open"
5929
5930 return i;
5931}
5932
5933static void
5934cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev,
5935 PTACHYON fcChip,
5936 ULONG x_ID)
5937{
5938 // Unmaps the memory regions used to hold the scatter gather lists
5939
5940 PSGPAGES i;
5941
5942 // Were there any such regions needing unmapping?
5943 if (! USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
5944 return; // No such regions, we're outta here.
5945
5946 // for each extended scatter gather region needing unmapping...
5947 for (i=fcChip->SEST->sgPages[x_ID] ; i != NULL ; i = i->next)
5948 pci_unmap_single(pcidev, i->busaddr, i->maplen,
5949 PCI_DMA_TODEVICE);
5950}
5951
5952// Called also from cpqfcTScontrol.o, so can't be static
5953void
5954cpqfc_pci_unmap(struct pci_dev *pcidev,
5955 Scsi_Cmnd *cmd,
5956 PTACHYON fcChip,
5957 ULONG x_ID)
5958{
5959 // Undo the DMA mappings
5960 if (cmd->use_sg) { // Used scatter gather list for data buffer?
5961 cpqfc_pci_unmap_extended_sg(pcidev, fcChip, x_ID);
5962 pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg,
5963 cmd->sc_data_direction);
5964 // printk("umsg %d\n", cmd->use_sg);
5965 }
5966 else if (cmd->request_bufflen) {
5967 // printk("ums %p ", fcChip->SEST->u[ x_ID ].IWE.GAddr1);
5968 pci_unmap_single(pcidev, fcChip->SEST->u[ x_ID ].IWE.GAddr1,
5969 cmd->request_bufflen,
5970 cmd->sc_data_direction);
5971 }
5972}
5973
5974// We call this routine to free an Exchange for any reason:
5975// completed successfully, completed with error, aborted, etc.
5976
5977// returns FALSE if Exchange failed and "retry" is acceptable
5978// returns TRUE if Exchange was successful, or retry is impossible
5979// (e.g. port/device gone).
5980//scompleteexchange
5981
5982void cpqfcTSCompleteExchange(
5983 struct pci_dev *pcidev,
5984 PTACHYON fcChip,
5985 ULONG x_ID)
5986{
5987 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5988 int already_unmapped = 0;
5989
5990 if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange)
5991 {
5992 if( Exchanges->fcExchange[ x_ID ].Cmnd == NULL ) // what#@!
5993 {
5994// TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
5995 printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID,
5996 Exchanges->fcExchange[ x_ID ].type);
5997
5998 goto CleanUpSestResources; // this path should be very rare.
5999 }
6000
6001 // we have Linux Scsi Cmnd ptr..., now check our Exchange status
6002 // to decide how to complete this SEST FCP exchange
6003
6004 if( Exchanges->fcExchange[ x_ID ].status ) // perhaps a Tach indicated problem,
6005 // or abnormal exchange completion
6006 {
6007 // set FCP Link statistics
6008
6009 if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
6010 fcChip->fcStats.timeouts++;
6011 if( Exchanges->fcExchange[ x_ID ].status & INITIATOR_ABORT)
6012 fcChip->fcStats.FC4aborted++;
6013 if( Exchanges->fcExchange[ x_ID ].status & COUNT_ERROR)
6014 fcChip->fcStats.CntErrors++;
6015 if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX)
6016 fcChip->fcStats.linkFailTX++;
6017 if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_RX)
6018 fcChip->fcStats.linkFailRX++;
6019 if( Exchanges->fcExchange[ x_ID ].status & OVERFLOW)
6020 fcChip->fcStats.CntErrors++;
6021
6022 // First, see if the Scsi upper level initiated an ABORT on this
6023 // exchange...
6024 if( Exchanges->fcExchange[ x_ID ].status == INITIATOR_ABORT )
6025 {
6026 printk(" DID_ABORT, x_ID %Xh, Cmnd %p ",
6027 x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
6028 goto CleanUpSestResources; // (we don't expect Linux _aborts)
6029 }
6030
6031 // Did our driver timeout the Exchange, or did Tachyon indicate
6032 // a failure during transmission? Ask for retry with "SOFT_ERROR"
6033 else if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
6034 {
6035// printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
6036// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
6037 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
6038 }
6039
6040 // Did frame(s) for an open exchange arrive in the SFQ,
6041 // meaning the SEST was unable to process them?
6042 else if( Exchanges->fcExchange[ x_ID ].status & SFQ_FRAME)
6043 {
6044// printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
6045// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
6046 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
6047 }
6048
6049 // Did our driver timeout the Exchange, or did Tachyon indicate
6050 // a failure during transmission? Ask for retry with "SOFT_ERROR"
6051 else if(
6052 (Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) ||
6053 (Exchanges->fcExchange[ x_ID ].status & PORTID_CHANGED) ||
6054 (Exchanges->fcExchange[ x_ID ].status & FRAME_TO) ||
6055 (Exchanges->fcExchange[ x_ID ].status & INV_ENTRY) ||
6056 (Exchanges->fcExchange[ x_ID ].status & ABORTSEQ_NOTIFY) )
6057
6058
6059 {
6060// printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
6061// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
6062 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
6063
6064
6065 }
6066
6067 // e.g., a LOGOut happened, or device never logged back in.
6068 else if( Exchanges->fcExchange[ x_ID ].status & DEVICE_REMOVED)
6069 {
6070// printk(" *LOGOut or timeout on login!* ");
6071 // trigger?
6072// TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
6073
6074 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_BAD_TARGET <<16);
6075 }
6076
6077
6078 // Did Tachyon indicate a CNT error? We need further analysis
6079 // to determine if the exchange is acceptable
6080 else if( Exchanges->fcExchange[ x_ID ].status == COUNT_ERROR)
6081 {
6082 UCHAR ScsiStatus;
6083 FCP_STATUS_RESPONSE *pFcpStatus =
6084 (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
6085
6086 ScsiStatus = pFcpStatus->fcp_status >>24;
6087
6088 // If the command is a SCSI Read/Write type, we don't tolerate
6089 // count errors of any kind; assume the count error is due to
6090 // a dropped frame and ask for retry...
6091
6092 if(( (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x8) ||
6093 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x28) ||
6094 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0xA) ||
6095 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x2A) )
6096 &&
6097 ScsiStatus == 0 )
6098 {
6099 // ask for retry
6100/* printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n",
6101 x_ID, Exchanges->fcExchange[ x_ID ].status,
6102 Exchanges->fcExchange[ x_ID ].Cmnd);*/
6103 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
6104 }
6105
6106 else // need more analysis
6107 {
6108 cpqfcTSCheckandSnoopFCP(fcChip, x_ID); // (will set ->result)
6109 }
6110 }
6111
6112 // default: NOTE! We don't ever want to get here. Getting here
6113 // implies something new is happening that we've never had a test
6114 // case for. Need code maintenance! Return "ERROR"
6115 else
6116 {
6117 unsigned int stat = Exchanges->fcExchange[ x_ID ].status;
6118 printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p",
6119 Exchanges->fcExchange[ x_ID ].status, x_ID,
6120 Exchanges->fcExchange[ x_ID ].Cmnd);
6121
6122 if (stat & INVALID_ARGS) printk(" INVALID_ARGS ");
6123 if (stat & LNKDWN_OSLS) printk(" LNKDWN_OSLS ");
6124 if (stat & LNKDWN_LASER) printk(" LNKDWN_LASER ");
6125 if (stat & OUTQUE_FULL) printk(" OUTQUE_FULL ");
6126 if (stat & DRIVERQ_FULL) printk(" DRIVERQ_FULL ");
6127 if (stat & SEST_FULL) printk(" SEST_FULL ");
6128 if (stat & BAD_ALPA) printk(" BAD_ALPA ");
6129 if (stat & OVERFLOW) printk(" OVERFLOW ");
6130 if (stat & COUNT_ERROR) printk(" COUNT_ERROR ");
6131 if (stat & LINKFAIL_RX) printk(" LINKFAIL_RX ");
6132 if (stat & ABORTSEQ_NOTIFY) printk(" ABORTSEQ_NOTIFY ");
6133 if (stat & LINKFAIL_TX) printk(" LINKFAIL_TX ");
6134 if (stat & HOSTPROG_ERR) printk(" HOSTPROG_ERR ");
6135 if (stat & FRAME_TO) printk(" FRAME_TO ");
6136 if (stat & INV_ENTRY) printk(" INV_ENTRY ");
6137 if (stat & SESTPROG_ERR) printk(" SESTPROG_ERR ");
6138 if (stat & OUTBOUND_TIMEOUT) printk(" OUTBOUND_TIMEOUT ");
6139 if (stat & INITIATOR_ABORT) printk(" INITIATOR_ABORT ");
6140 if (stat & MEMPOOL_FAIL) printk(" MEMPOOL_FAIL ");
6141 if (stat & FC2_TIMEOUT) printk(" FC2_TIMEOUT ");
6142 if (stat & TARGET_ABORT) printk(" TARGET_ABORT ");
6143 if (stat & EXCHANGE_QUEUED) printk(" EXCHANGE_QUEUED ");
6144 if (stat & PORTID_CHANGED) printk(" PORTID_CHANGED ");
6145 if (stat & DEVICE_REMOVED) printk(" DEVICE_REMOVED ");
6146 if (stat & SFQ_FRAME) printk(" SFQ_FRAME ");
6147 printk("\n");
6148
6149 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16);
6150 }
6151 }
6152 else // definitely no Tach problem, but perhaps an FCP problem
6153 {
6154 // set FCP Link statistic
6155 fcChip->fcStats.ok++;
6156 cpqfcTSCheckandSnoopFCP( fcChip, x_ID); // (will set ->result)
6157 }
6158
6159 cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd,
6160 fcChip, x_ID); // undo DMA mappings.
6161 already_unmapped = 1;
6162
6163 // OK, we've set the Scsi "->result" field, so proceed with calling
6164 // Linux Scsi "done" (if not NULL), and free any kernel memory we
6165 // may have allocated for the exchange.
6166
6167 PCI_TRACEO( (ULONG)Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
6168 // complete the command back to upper Scsi drivers
6169 if( Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done != NULL)
6170 {
6171 // Calling "done" on an Linux _abort() aborted
6172 // Cmnd causes a kernel panic trying to re-free mem.
6173 // Actually, we shouldn't do anything with an _abort CMND
6174 if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) )
6175 {
6176 PCI_TRACE(0xAC)
6177 call_scsi_done(Exchanges->fcExchange[ x_ID ].Cmnd);
6178 }
6179 else
6180 {
6181// printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
6182// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
6183 }
6184 }
6185 else{
6186 printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
6187 Exchanges->fcExchange[ x_ID ].type,
6188 Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);
6189 printk(" cpqfcTS: Null scsi_done function pointer!\n");
6190 }
6191
6192
6193 // Now, clean up non-Scsi_Cmnd items...
6194CleanUpSestResources:
6195
6196 if (!already_unmapped)
6197 cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd,
6198 fcChip, x_ID); // undo DMA mappings.
6199
6200 // Was an Extended Scatter/Gather page allocated? We know
6201 // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
6202 if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000))
6203 {
6204 PSGPAGES p, next;
6205
6206 // extended S/G list was used -- Free the allocated ext. S/G pages
6207 for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
6208 next = p->next;
6209 kfree(p);
6210 }
6211 fcChip->SEST->sgPages[x_ID] = NULL;
6212 }
6213
6214 Exchanges->fcExchange[ x_ID ].Cmnd = NULL;
6215 } // Done with FCP (SEST) exchanges
6216
6217
6218 // the remaining logic is common to ALL Exchanges:
6219 // FCP(SEST) and LinkServ.
6220
6221 Exchanges->fcExchange[ x_ID ].type = 0; // there -- FREE!
6222 Exchanges->fcExchange[ x_ID ].status = 0;
6223
6224 PCI_TRACEO( x_ID, 0xAC)
6225
6226
6227 return;
6228} // (END of CompleteExchange function)
6229
6230
6231
6232
6233// Unfortunately, we must snoop all command completions in
6234// order to manipulate certain return fields, and take note of
6235// device types, etc., to facilitate the Fibre-Channel to SCSI
6236// "mapping".
6237// (Watch for BIG Endian confusion on some payload fields)
6238void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID)
6239{
6240 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
6241 Scsi_Cmnd *Cmnd = Exchanges->fcExchange[ x_ID].Cmnd;
6242 FCP_STATUS_RESPONSE *pFcpStatus =
6243 (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
6244 UCHAR ScsiStatus;
6245
6246 ScsiStatus = pFcpStatus->fcp_status >>24;
6247
6248#ifdef FCP_COMPLETION_DBG
6249 printk("ScsiStatus = 0x%X\n", ScsiStatus);
6250#endif
6251
6252 // First, check FCP status
6253 if( pFcpStatus->fcp_status & FCP_RSP_LEN_VALID )
6254 {
6255 // check response code (RSP_CODE) -- most popular is bad len
6256 // 1st 4 bytes of rsp info -- only byte 3 interesting
6257 if( pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN )
6258 {
6259
6260 // do we EVER get here?
6261 printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
6262 }
6263 }
6264
6265 // for now, go by the ScsiStatus, and manipulate certain
6266 // commands when necessary...
6267 if( ScsiStatus == 0) // SCSI status byte "good"?
6268 {
6269 Cmnd->result = 0; // everything's OK
6270
6271 if( (Cmnd->cmnd[0] == INQUIRY))
6272 {
6273 UCHAR *InquiryData = Cmnd->request_buffer;
6274 PFC_LOGGEDIN_PORT pLoggedInPort;
6275
6276 // We need to manipulate INQUIRY
6277 // strings for COMPAQ RAID controllers to force
6278 // Linux to scan additional LUNs. Namely, set
6279 // the Inquiry string byte 2 (ANSI-approved version)
6280 // to 2.
6281
6282 if( !memcmp( &InquiryData[8], "COMPAQ", 6 ))
6283 {
6284 InquiryData[2] = 0x2; // claim SCSI-2 compliance,
6285 // so multiple LUNs may be scanned.
6286 // (no SCSI-2 problems known in CPQ)
6287 }
6288
6289 // snoop the Inquiry to detect Disk, Tape, etc. type
6290 // (search linked list for the port_id we sent INQUIRY to)
6291 pLoggedInPort = fcFindLoggedInPort( fcChip,
6292 NULL, // DON'T search Scsi Nexus (we will set it)
6293 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,
6294 NULL, // DON'T search linked list for FC WWN
6295 NULL); // DON'T care about end of list
6296
6297 if( pLoggedInPort )
6298 {
6299 pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
6300 }
6301 else
6302 {
6303 printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n",
6304 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
6305 }
6306 }
6307 }
6308
6309
6310 // Scsi Status not good -- pass it back to caller
6311
6312 else
6313 {
6314 Cmnd->result = ScsiStatus; // SCSI status byte is 1st
6315
6316 // check for valid "sense" data
6317
6318 if( pFcpStatus->fcp_status & FCP_SNS_LEN_VALID )
6319 { // limit Scsi Sense field length!
6320 int SenseLen = pFcpStatus->fcp_sns_len >>24; // (BigEndian) lower byte
6321
6322 SenseLen = SenseLen > sizeof( Cmnd->sense_buffer) ?
6323 sizeof( Cmnd->sense_buffer) : SenseLen;
6324
6325
6326#ifdef FCP_COMPLETION_DBG
6327 printk("copy sense_buffer %p, len %d, result %Xh\n",
6328 Cmnd->sense_buffer, SenseLen, Cmnd->result);
6329#endif
6330
6331 // NOTE: There is some dispute over the FCP response
6332 // format. Most FC devices assume that FCP_RSP_INFO
6333 // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
6334 // is (virtually) always 0 and the field is "invalid".
6335 // Some other devices assume that
6336 // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
6337 // when the FCP_RSP is invalid (this almost appears to be
6338 // one of those "religious" issues).
6339 // Consequently, we test the usual position of FCP_SNS_INFO
6340 // for 7Xh, since the SCSI sense format says the first
6341 // byte ("error code") should be 0x70 or 0x71. In practice,
6342 // we find that every device does in fact have 0x70 or 0x71
6343 // in the first byte position, so this test works for all
6344 // FC devices.
6345 // (This logic is especially effective for the CPQ/DEC HSG80
6346 // & HSG60 controllers).
6347
6348 if( (pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70 )
6349 memcpy( Cmnd->sense_buffer,
6350 &pFcpStatus->fcp_sns_info[0], SenseLen);
6351 else
6352 {
6353 unsigned char *sbPtr =
6354 (unsigned char *)&pFcpStatus->fcp_sns_info[0];
6355 sbPtr -= 8; // back up 8 bytes hoping to find the
6356 // start of the sense buffer
6357 memcpy( Cmnd->sense_buffer, sbPtr, SenseLen);
6358 }
6359
6360 // in the special case of Device Reset, tell upper layer
6361 // to immediately retry (with SOFT_ERROR status)
6362 // look for Sense Key Unit Attention (0x6) with ASC Device
6363 // Reset (0x29)
6364 // printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
6365 // SenseLen, Cmnd->sense_buffer[2],
6366 // Cmnd->sense_buffer[12]);
6367 if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
6368 (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
6369 {
6370 Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
6371 }
6372
6373 // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
6374 else if( ((Cmnd->sense_buffer[2] & 0xF) == 0x4) && // "hardware error"
6375 (Cmnd->sense_buffer[12] == 0x44) ) // Addtl. Sense Code
6376 {
6377// printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n",
6378// Cmnd->channel, Cmnd->target, Cmnd->lun);
6379 Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
6380 }
6381
6382 } // (end of sense len valid)
6383
6384 // there is no sense data to help out Linux's Scsi layers...
6385 // We'll just return the Scsi status and hope he will "do the
6386 // right thing"
6387 else
6388 {
6389 // as far as we know, the Scsi status is sufficient
6390 Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
6391 }
6392 }
6393}
6394
6395
6396
6397//PPPPPPPPPPPPPPPPPPPPPPPPP PAYLOAD PPPPPPPPP
6398// build data PAYLOAD; SCSI FCP_CMND I.U.
6399// remember BIG ENDIAN payload - DWord values must be byte-reversed
6400// (hence the affinity for byte pointer building).
6401
6402static int build_FCP_payload( Scsi_Cmnd *Cmnd,
6403 UCHAR* payload, ULONG type, ULONG fcp_dl )
6404{
6405 int i;
6406
6407
6408 switch( type)
6409 {
6410
6411 case SCSI_IWE:
6412 case SCSI_IRE:
6413 // 8 bytes FCP_LUN
6414 // Peripheral Device or Volume Set addressing, and LUN mapping
6415 // When the FC port was looked up, we copied address mode
6416 // and any LUN mask to the scratch pad SCp.phase & .mode
6417
6418 *payload++ = (UCHAR)Cmnd->SCp.phase;
6419
6420 // Now, because of "lun masking"
6421 // (aka selective storage presentation),
6422 // the contiguous Linux Scsi lun number may not match the
6423 // device's lun number, so we may have to "map".
6424
6425 *payload++ = (UCHAR)Cmnd->SCp.have_data_in;
6426
6427 // We don't know of anyone in the FC business using these
6428 // extra "levels" of addressing. In fact, confusion still exists
6429 // just using the FIRST level... ;-)
6430
6431 *payload++ = 0; // 2nd level addressing
6432 *payload++ = 0;
6433 *payload++ = 0; // 3rd level addressing
6434 *payload++ = 0;
6435 *payload++ = 0; // 4th level addressing
6436 *payload++ = 0;
6437
6438 // 4 bytes Control Field FCP_CNTL
6439 *payload++ = 0; // byte 0: (MSB) reserved
6440 *payload++ = 0; // byte 1: task codes
6441
6442 // byte 2: task management flags
6443 // another "use" of the spare field to accomplish TDR
6444 // note combination needed
6445 if( (Cmnd->cmnd[0] == RELEASE) &&
6446 (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) )
6447 {
6448 Cmnd->cmnd[0] = 0; // issue "Test Unit Ready" for TDR
6449 *payload++ = 0x20; // target device reset bit
6450 }
6451 else
6452 *payload++ = 0; // no TDR
6453 // byte 3: (LSB) execution management codes
6454 // bit 0 write, bit 1 read (don't set together)
6455
6456 if( fcp_dl != 0 )
6457 {
6458 if( type == SCSI_IWE ) // WRITE
6459 *payload++ = 1;
6460 else // READ
6461 *payload++ = 2;
6462 }
6463 else
6464 {
6465 // On some devices, if RD or WR bits are set,
6466 // and fcp_dl is 0, they will generate an error on the command.
6467 // (i.e., if direction is specified, they insist on a length).
6468 *payload++ = 0; // no data (necessary for CPQ)
6469 }
6470
6471
6472 // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
6473 // FCP_CDB allows 16 byte SCSI command descriptor blk;
6474 // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
6475 for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
6476 *payload++ = Cmnd->cmnd[i];
6477
6478 // if( Cmnd->cmd_len == 16 )
6479 // {
6480 // memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
6481 // }
6482 payload+= (16 - i);
6483
6484 // FCP_DL is largest number of expected data bytes
6485 // per CDB (i.e. read/write command)
6486 *payload++ = (UCHAR)(fcp_dl >>24); // (MSB) 8 bytes data len FCP_DL
6487 *payload++ = (UCHAR)(fcp_dl >>16);
6488 *payload++ = (UCHAR)(fcp_dl >>8);
6489 *payload++ = (UCHAR)fcp_dl; // (LSB)
6490 break;
6491
6492 case SCSI_TWE: // need FCP_XFER_RDY
6493 *payload++ = 0; // (4 bytes) DATA_RO (MSB byte 0)
6494 *payload++ = 0;
6495 *payload++ = 0;
6496 *payload++ = 0; // LSB (byte 3)
6497 // (4 bytes) BURST_LEN
6498 // size of following FCP_DATA payload
6499 *payload++ = (UCHAR)(fcp_dl >>24); // (MSB) 8 bytes data len FCP_DL
6500 *payload++ = (UCHAR)(fcp_dl >>16);
6501 *payload++ = (UCHAR)(fcp_dl >>8);
6502 *payload++ = (UCHAR)fcp_dl; // (LSB)
6503 // 4 bytes RESERVED
6504 *payload++ = 0;
6505 *payload++ = 0;
6506 *payload++ = 0;
6507 *payload++ = 0;
6508 break;
6509
6510 default:
6511 break;
6512 }
6513
6514 return 0;
6515}
6516