diff options
Diffstat (limited to 'drivers/fc4')
-rw-r--r-- | drivers/fc4/Kconfig | 81 | ||||
-rw-r--r-- | drivers/fc4/Makefile | 9 | ||||
-rw-r--r-- | drivers/fc4/fc-al.h | 27 | ||||
-rw-r--r-- | drivers/fc4/fc.c | 1146 | ||||
-rw-r--r-- | drivers/fc4/fc.h | 230 | ||||
-rw-r--r-- | drivers/fc4/fc_syms.c | 30 | ||||
-rw-r--r-- | drivers/fc4/fcp.h | 94 | ||||
-rw-r--r-- | drivers/fc4/fcp_impl.h | 164 | ||||
-rw-r--r-- | drivers/fc4/soc.c | 764 | ||||
-rw-r--r-- | drivers/fc4/soc.h | 301 | ||||
-rw-r--r-- | drivers/fc4/socal.c | 904 | ||||
-rw-r--r-- | drivers/fc4/socal.h | 314 |
12 files changed, 0 insertions, 4064 deletions
diff --git a/drivers/fc4/Kconfig b/drivers/fc4/Kconfig deleted file mode 100644 index 345dbe6f10df..000000000000 --- a/drivers/fc4/Kconfig +++ /dev/null | |||
@@ -1,81 +0,0 @@ | |||
1 | # | ||
2 | # FC4 device configuration | ||
3 | # | ||
4 | |||
5 | menu "Fibre Channel support" | ||
6 | |||
7 | config FC4 | ||
8 | tristate "Fibre Channel and FC4 SCSI support" | ||
9 | ---help--- | ||
10 | Fibre Channel is a high speed serial protocol mainly used to | ||
11 | connect large storage devices to the computer; it is compatible with | ||
12 | and intended to replace SCSI. | ||
13 | |||
14 | This is an experimental support for storage arrays connected to your | ||
15 | computer using optical fibre cables and the "X3.269-199X Fibre | ||
16 | Channel Protocol for SCSI" specification. If you want to use this, | ||
17 | you need to say Y here and to "SCSI support" as well as to the | ||
18 | drivers for the storage array itself and for the interface adapter | ||
19 | such as SOC or SOC+. This subsystem could even serve for IP | ||
20 | networking, with some code extensions. | ||
21 | |||
22 | If unsure, say N. | ||
23 | |||
24 | comment "FC4 drivers" | ||
25 | depends on FC4 | ||
26 | |||
27 | config FC4_SOC | ||
28 | tristate "Sun SOC/Sbus" | ||
29 | depends on FC4!=n && SPARC | ||
30 | help | ||
31 | Serial Optical Channel is an interface card with one or two Fibre | ||
32 | Optic ports, each of which can be connected to a disk array. Note | ||
33 | that if you have older firmware in the card, you'll need the | ||
34 | microcode from the Solaris driver to make it work. | ||
35 | |||
36 | To compile this support as a module, choose M here: the module will | ||
37 | be called soc. | ||
38 | |||
39 | config FC4_SOCAL | ||
40 | tristate "Sun SOC+ (aka SOCAL)" | ||
41 | depends on FC4!=n && SPARC | ||
42 | ---help--- | ||
43 | Serial Optical Channel Plus is an interface card with up to two | ||
44 | Fibre Optic ports. This card supports FC Arbitrated Loop (usually | ||
45 | A5000 or internal FC disks in E[3-6]000 machines through the | ||
46 | Interface Board). You'll probably need the microcode from the | ||
47 | Solaris driver to make it work. | ||
48 | |||
49 | To compile this support as a module, choose M here: the module will | ||
50 | be called socal. | ||
51 | |||
52 | comment "FC4 targets" | ||
53 | depends on FC4 | ||
54 | |||
55 | config SCSI_PLUTO | ||
56 | tristate "SparcSTORAGE Array 100 and 200 series" | ||
57 | depends on FC4!=n && SCSI | ||
58 | help | ||
59 | If you never bought a disk array made by Sun, go with N. | ||
60 | |||
61 | To compile this support as a module, choose M here: the module will | ||
62 | be called pluto. | ||
63 | |||
64 | config SCSI_FCAL | ||
65 | tristate "Sun Enterprise Network Array (A5000 and EX500)" if SPARC | ||
66 | depends on FC4!=n && SCSI | ||
67 | help | ||
68 | This driver drives FC-AL disks connected through a Fibre Channel | ||
69 | card using the drivers/fc4 layer (currently only SOCAL). The most | ||
70 | common is either A5000 array or internal disks in E[3-6]000 | ||
71 | machines. | ||
72 | |||
73 | To compile this support as a module, choose M here: the module will | ||
74 | be called fcal. | ||
75 | |||
76 | config SCSI_FCAL | ||
77 | prompt "Generic FC-AL disk driver" | ||
78 | depends on FC4!=n && SCSI && !SPARC | ||
79 | |||
80 | endmenu | ||
81 | |||
diff --git a/drivers/fc4/Makefile b/drivers/fc4/Makefile deleted file mode 100644 index 0db3fbb553e9..000000000000 --- a/drivers/fc4/Makefile +++ /dev/null | |||
@@ -1,9 +0,0 @@ | |||
1 | # | ||
2 | # Makefile for the Linux Fibre Channel device drivers. | ||
3 | # | ||
4 | |||
5 | fc4-objs := fc.o fc_syms.o | ||
6 | |||
7 | obj-$(CONFIG_FC4) += fc4.o | ||
8 | obj-$(CONFIG_FC4_SOC) += soc.o | ||
9 | obj-$(CONFIG_FC4_SOCAL) += socal.o | ||
diff --git a/drivers/fc4/fc-al.h b/drivers/fc4/fc-al.h deleted file mode 100644 index 62d3ca436d72..000000000000 --- a/drivers/fc4/fc-al.h +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | /* fc-al.h: Definitions for Fibre Channel Arbitrated Loop topology. | ||
2 | * | ||
3 | * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
4 | * | ||
5 | * Sources: | ||
6 | * Fibre Channel Arbitrated Loop (FC-AL), ANSI, Rev. 4.5, 1995 | ||
7 | */ | ||
8 | |||
9 | #ifndef __FC_AL_H | ||
10 | #define __FC_AL_H | ||
11 | |||
12 | /* Loop initialization payloads */ | ||
13 | #define FC_AL_LISM 0x11010000 /* Select Master, 12B payload */ | ||
14 | #define FC_AL_LIFA 0x11020000 /* Fabric Assign AL_PA bitmap, 20B payload */ | ||
15 | #define FC_AL_LIPA 0x11030000 /* Previously Acquired AL_PA bitmap, 20B payload */ | ||
16 | #define FC_AL_LIHA 0x11040000 /* Hard Assigned AL_PA bitmap, 20B payload */ | ||
17 | #define FC_AL_LISA 0x11050000 /* Soft Assigned AL_PA bitmap, 20B payload */ | ||
18 | #define FC_AL_LIRP 0x11060000 /* Report AL_PA position map, 132B payload */ | ||
19 | #define FC_AL_LILP 0x11070000 /* Loop AL_PA position map, 132B payload */ | ||
20 | |||
21 | typedef struct { | ||
22 | u32 magic; | ||
23 | u8 len; | ||
24 | u8 alpa[127]; | ||
25 | } fc_al_posmap; | ||
26 | |||
27 | #endif /* !(__FC_H) */ | ||
diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c deleted file mode 100644 index 82de9e1adb1e..000000000000 --- a/drivers/fc4/fc.c +++ /dev/null | |||
@@ -1,1146 +0,0 @@ | |||
1 | /* fc.c: Generic Fibre Channel and FC4 SCSI driver. | ||
2 | * | ||
3 | * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz) | ||
4 | * Copyright (C) 1997,1998 Jirka Hanika (geo@ff.cuni.cz) | ||
5 | * | ||
6 | * There are two kinds of Fibre Channel adapters used in Linux. Either | ||
7 | * the adapter is "smart" and does all FC bookkeeping by itself and | ||
8 | * just presents a standard SCSI interface to the operating system | ||
9 | * (that's e.g. the case with Qlogic FC cards), or leaves most of the FC | ||
10 | * bookkeeping to the OS (e.g. soc, socal). Drivers for the former adapters | ||
11 | * will look like normal SCSI drivers (with the exception of max_id will be | ||
12 | * usually 127), the latter on the other side allows SCSI, IP over FC and other | ||
13 | * protocols. This driver tree is for the latter adapters. | ||
14 | * | ||
15 | * This file should support both Point-to-Point and Arbitrated Loop topologies. | ||
16 | * | ||
17 | * Sources: | ||
18 | * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994 | ||
19 | * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995 | ||
20 | * Fibre Channel Arbitrated Loop (FC-AL), Rev. 4.5, 1995 | ||
21 | * Fibre Channel Private Loop SCSI Direct Attach (FC-PLDA), Rev. 2.1, 1997 | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/jiffies.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/fcntl.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/ptrace.h> | ||
31 | #include <linux/ioport.h> | ||
32 | #include <linux/in.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/string.h> | ||
35 | #include <linux/init.h> | ||
36 | |||
37 | #include <asm/pgtable.h> | ||
38 | #include <asm/irq.h> | ||
39 | #include <asm/semaphore.h> | ||
40 | #include "fcp_impl.h" | ||
41 | #include <scsi/scsi_host.h> | ||
42 | |||
43 | /* #define FCDEBUG */ | ||
44 | |||
45 | #define fc_printk printk ("%s: ", fc->name); printk | ||
46 | |||
47 | #ifdef FCDEBUG | ||
48 | #define FCD(x) fc_printk x; | ||
49 | #define FCND(x) printk ("FC: "); printk x; | ||
50 | #else | ||
51 | #define FCD(x) | ||
52 | #define FCND(x) | ||
53 | #endif | ||
54 | |||
55 | #ifdef __sparc__ | ||
56 | #define dma_alloc_consistent(d,s,p) sbus_alloc_consistent(d,s,p) | ||
57 | #define dma_free_consistent(d,s,v,h) sbus_free_consistent(d,s,v,h) | ||
58 | #define dma_map_single(d,v,s,dir) sbus_map_single(d,v,s,dir) | ||
59 | #define dma_unmap_single(d,h,s,dir) sbus_unmap_single(d,h,s,dir) | ||
60 | #define dma_map_sg(d,s,n,dir) sbus_map_sg(d,s,n,dir) | ||
61 | #define dma_unmap_sg(d,s,n,dir) sbus_unmap_sg(d,s,n,dir) | ||
62 | #else | ||
63 | #define dma_alloc_consistent(d,s,p) pci_alloc_consistent(d,s,p) | ||
64 | #define dma_free_consistent(d,s,v,h) pci_free_consistent(d,s,v,h) | ||
65 | #define dma_map_single(d,v,s,dir) pci_map_single(d,v,s,dir) | ||
66 | #define dma_unmap_single(d,h,s,dir) pci_unmap_single(d,h,s,dir) | ||
67 | #define dma_map_sg(d,s,n,dir) pci_map_sg(d,s,n,dir) | ||
68 | #define dma_unmap_sg(d,s,n,dir) pci_unmap_sg(d,s,n,dir) | ||
69 | #endif | ||
70 | |||
71 | #define FCP_CMND(SCpnt) ((fcp_cmnd *)&(SCpnt->SCp)) | ||
72 | #define FC_SCMND(SCpnt) ((fc_channel *)(SCpnt->device->host->hostdata[0])) | ||
73 | #define SC_FCMND(fcmnd) ((struct scsi_cmnd *)((long)fcmnd - (long)&(((struct scsi_cmnd *)0)->SCp))) | ||
74 | |||
75 | static int fcp_scsi_queue_it(fc_channel *, struct scsi_cmnd *, fcp_cmnd *, int); | ||
76 | void fcp_queue_empty(fc_channel *); | ||
77 | |||
78 | static void fcp_scsi_insert_queue (fc_channel *fc, fcp_cmnd *fcmd) | ||
79 | { | ||
80 | if (!fc->scsi_que) { | ||
81 | fc->scsi_que = fcmd; | ||
82 | fcmd->next = fcmd; | ||
83 | fcmd->prev = fcmd; | ||
84 | } else { | ||
85 | fc->scsi_que->prev->next = fcmd; | ||
86 | fcmd->prev = fc->scsi_que->prev; | ||
87 | fc->scsi_que->prev = fcmd; | ||
88 | fcmd->next = fc->scsi_que; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | static void fcp_scsi_remove_queue (fc_channel *fc, fcp_cmnd *fcmd) | ||
93 | { | ||
94 | if (fcmd == fcmd->next) { | ||
95 | fc->scsi_que = NULL; | ||
96 | return; | ||
97 | } | ||
98 | if (fcmd == fc->scsi_que) | ||
99 | fc->scsi_que = fcmd->next; | ||
100 | fcmd->prev->next = fcmd->next; | ||
101 | fcmd->next->prev = fcmd->prev; | ||
102 | } | ||
103 | |||
104 | fc_channel *fc_channels = NULL; | ||
105 | |||
106 | #define LSMAGIC 620829043 | ||
107 | typedef struct { | ||
108 | /* Must be first */ | ||
109 | struct semaphore sem; | ||
110 | int magic; | ||
111 | int count; | ||
112 | logi *logi; | ||
113 | fcp_cmnd *fcmds; | ||
114 | atomic_t todo; | ||
115 | struct timer_list timer; | ||
116 | unsigned char grace[0]; | ||
117 | } ls; | ||
118 | |||
119 | #define LSOMAGIC 654907799 | ||
120 | typedef struct { | ||
121 | /* Must be first */ | ||
122 | struct semaphore sem; | ||
123 | int magic; | ||
124 | int count; | ||
125 | fcp_cmnd *fcmds; | ||
126 | atomic_t todo; | ||
127 | struct timer_list timer; | ||
128 | } lso; | ||
129 | |||
130 | #define LSEMAGIC 84482456 | ||
131 | typedef struct { | ||
132 | /* Must be first */ | ||
133 | struct semaphore sem; | ||
134 | int magic; | ||
135 | int status; | ||
136 | struct timer_list timer; | ||
137 | } lse; | ||
138 | |||
139 | static void fcp_login_timeout(unsigned long data) | ||
140 | { | ||
141 | ls *l = (ls *)data; | ||
142 | FCND(("Login timeout\n")) | ||
143 | up(&l->sem); | ||
144 | } | ||
145 | |||
146 | static void fcp_login_done(fc_channel *fc, int i, int status) | ||
147 | { | ||
148 | fcp_cmnd *fcmd; | ||
149 | logi *plogi; | ||
150 | fc_hdr *fch; | ||
151 | ls *l = (ls *)fc->ls; | ||
152 | |||
153 | FCD(("Login done %d %d\n", i, status)) | ||
154 | if (i < l->count) { | ||
155 | if (fc->state == FC_STATE_FPORT_OK) { | ||
156 | FCD(("Additional FPORT_OK received with status %d\n", status)) | ||
157 | return; | ||
158 | } | ||
159 | switch (status) { | ||
160 | case FC_STATUS_OK: /* Oh, we found a fabric */ | ||
161 | case FC_STATUS_P_RJT: /* Oh, we haven't found any */ | ||
162 | fc->state = FC_STATE_FPORT_OK; | ||
163 | fcmd = l->fcmds + i; | ||
164 | plogi = l->logi + 3 * i; | ||
165 | dma_unmap_single (fc->dev, fcmd->cmd, 3 * sizeof(logi), | ||
166 | DMA_BIDIRECTIONAL); | ||
167 | plogi->code = LS_PLOGI; | ||
168 | memcpy (&plogi->nport_wwn, &fc->wwn_nport, sizeof(fc_wwn)); | ||
169 | memcpy (&plogi->node_wwn, &fc->wwn_node, sizeof(fc_wwn)); | ||
170 | memcpy (&plogi->common, fc->common_svc, sizeof(common_svc_parm)); | ||
171 | memcpy (&plogi->class1, fc->class_svcs, 3*sizeof(svc_parm)); | ||
172 | fch = &fcmd->fch; | ||
173 | fcmd->token += l->count; | ||
174 | FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, fc->did); | ||
175 | FILL_FCHDR_SID(fch, fc->sid); | ||
176 | #ifdef FCDEBUG | ||
177 | { | ||
178 | int i; | ||
179 | unsigned *x = (unsigned *)plogi; | ||
180 | printk ("logi: "); | ||
181 | for (i = 0; i < 21; i++) | ||
182 | printk ("%08x ", x[i]); | ||
183 | printk ("\n"); | ||
184 | } | ||
185 | #endif | ||
186 | fcmd->cmd = dma_map_single (fc->dev, plogi, 3 * sizeof(logi), | ||
187 | DMA_BIDIRECTIONAL); | ||
188 | fcmd->rsp = fcmd->cmd + 2 * sizeof(logi); | ||
189 | if (fc->hw_enque (fc, fcmd)) | ||
190 | printk ("FC: Cannot enque PLOGI packet on %s\n", fc->name); | ||
191 | break; | ||
192 | case FC_STATUS_ERR_OFFLINE: | ||
193 | fc->state = FC_STATE_MAYBEOFFLINE; | ||
194 | FCD (("FC is offline %d\n", l->grace[i])) | ||
195 | break; | ||
196 | default: | ||
197 | printk ("FLOGI failed for %s with status %d\n", fc->name, status); | ||
198 | /* Do some sort of error recovery here */ | ||
199 | break; | ||
200 | } | ||
201 | } else { | ||
202 | i -= l->count; | ||
203 | if (fc->state != FC_STATE_FPORT_OK) { | ||
204 | FCD(("Unexpected N-PORT rsp received")) | ||
205 | return; | ||
206 | } | ||
207 | switch (status) { | ||
208 | case FC_STATUS_OK: | ||
209 | plogi = l->logi + 3 * i; | ||
210 | dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), | ||
211 | DMA_BIDIRECTIONAL); | ||
212 | if (!fc->wwn_dest.lo && !fc->wwn_dest.hi) { | ||
213 | memcpy (&fc->wwn_dest, &plogi[1].node_wwn, sizeof(fc_wwn)); | ||
214 | FCD(("Dest WWN %08x%08x\n", *(u32 *)&fc->wwn_dest, fc->wwn_dest.lo)) | ||
215 | } else if (fc->wwn_dest.lo != plogi[1].node_wwn.lo || | ||
216 | fc->wwn_dest.hi != plogi[1].node_wwn.hi) { | ||
217 | printk ("%s: mismatch in wwns. Got %08x%08x, expected %08x%08x\n", | ||
218 | fc->name, | ||
219 | *(u32 *)&plogi[1].node_wwn, plogi[1].node_wwn.lo, | ||
220 | *(u32 *)&fc->wwn_dest, fc->wwn_dest.lo); | ||
221 | } | ||
222 | fc->state = FC_STATE_ONLINE; | ||
223 | printk ("%s: ONLINE\n", fc->name); | ||
224 | if (atomic_dec_and_test (&l->todo)) | ||
225 | up(&l->sem); | ||
226 | break; | ||
227 | case FC_STATUS_ERR_OFFLINE: | ||
228 | fc->state = FC_STATE_OFFLINE; | ||
229 | dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), | ||
230 | DMA_BIDIRECTIONAL); | ||
231 | printk ("%s: FC is offline\n", fc->name); | ||
232 | if (atomic_dec_and_test (&l->todo)) | ||
233 | up(&l->sem); | ||
234 | break; | ||
235 | default: | ||
236 | printk ("PLOGI failed for %s with status %d\n", fc->name, status); | ||
237 | /* Do some sort of error recovery here */ | ||
238 | break; | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | |||
243 | static void fcp_report_map_done(fc_channel *fc, int i, int status) | ||
244 | { | ||
245 | fcp_cmnd *fcmd; | ||
246 | fc_hdr *fch; | ||
247 | unsigned char j; | ||
248 | ls *l = (ls *)fc->ls; | ||
249 | fc_al_posmap *p; | ||
250 | |||
251 | FCD(("Report map done %d %d\n", i, status)) | ||
252 | switch (status) { | ||
253 | case FC_STATUS_OK: /* Ok, let's have a fun on a loop */ | ||
254 | dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), | ||
255 | DMA_BIDIRECTIONAL); | ||
256 | p = (fc_al_posmap *)(l->logi + 3 * i); | ||
257 | #ifdef FCDEBUG | ||
258 | { | ||
259 | u32 *u = (u32 *)p; | ||
260 | FCD(("%08x\n", u[0])) | ||
261 | u ++; | ||
262 | FCD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) | ||
263 | } | ||
264 | #endif | ||
265 | if ((p->magic & 0xffff0000) != FC_AL_LILP || !p->len) { | ||
266 | printk ("FC: Bad magic from REPORT_AL_MAP on %s - %08x\n", fc->name, p->magic); | ||
267 | fc->state = FC_STATE_OFFLINE; | ||
268 | } else { | ||
269 | fc->posmap = kzalloc(sizeof(fcp_posmap)+p->len, GFP_KERNEL); | ||
270 | if (!fc->posmap) { | ||
271 | printk("FC: Not enough memory, offlining channel\n"); | ||
272 | fc->state = FC_STATE_OFFLINE; | ||
273 | } else { | ||
274 | int k; | ||
275 | /* FIXME: This is where SOCAL transfers our AL-PA. | ||
276 | Keep it here till we found out what other cards do... */ | ||
277 | fc->sid = (p->magic & 0xff); | ||
278 | for (i = 0; i < p->len; i++) | ||
279 | if (p->alpa[i] == fc->sid) | ||
280 | break; | ||
281 | k = p->len; | ||
282 | if (i == p->len) | ||
283 | i = 0; | ||
284 | else { | ||
285 | p->len--; | ||
286 | i++; | ||
287 | } | ||
288 | fc->posmap->len = p->len; | ||
289 | for (j = 0; j < p->len; j++) { | ||
290 | if (i == k) i = 0; | ||
291 | fc->posmap->list[j] = p->alpa[i++]; | ||
292 | } | ||
293 | fc->state = FC_STATE_ONLINE; | ||
294 | } | ||
295 | } | ||
296 | printk ("%s: ONLINE\n", fc->name); | ||
297 | if (atomic_dec_and_test (&l->todo)) | ||
298 | up(&l->sem); | ||
299 | break; | ||
300 | case FC_STATUS_POINTTOPOINT: /* We're Point-to-Point, no AL... */ | ||
301 | FCD(("SID %d DID %d\n", fc->sid, fc->did)) | ||
302 | fcmd = l->fcmds + i; | ||
303 | dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi), | ||
304 | DMA_BIDIRECTIONAL); | ||
305 | fch = &fcmd->fch; | ||
306 | memset(l->logi + 3 * i, 0, 3 * sizeof(logi)); | ||
307 | FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT); | ||
308 | FILL_FCHDR_SID(fch, 0); | ||
309 | FILL_FCHDR_TYPE_FCTL(fch, TYPE_EXTENDED_LS, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); | ||
310 | FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); | ||
311 | FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); | ||
312 | fch->param = 0; | ||
313 | l->logi [3 * i].code = LS_FLOGI; | ||
314 | fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi), | ||
315 | DMA_BIDIRECTIONAL); | ||
316 | fcmd->rsp = fcmd->cmd + sizeof(logi); | ||
317 | fcmd->cmdlen = sizeof(logi); | ||
318 | fcmd->rsplen = sizeof(logi); | ||
319 | fcmd->data = (dma_addr_t)NULL; | ||
320 | fcmd->class = FC_CLASS_SIMPLE; | ||
321 | fcmd->proto = TYPE_EXTENDED_LS; | ||
322 | if (fc->hw_enque (fc, fcmd)) | ||
323 | printk ("FC: Cannot enque FLOGI packet on %s\n", fc->name); | ||
324 | break; | ||
325 | case FC_STATUS_ERR_OFFLINE: | ||
326 | fc->state = FC_STATE_MAYBEOFFLINE; | ||
327 | FCD (("FC is offline %d\n", l->grace[i])) | ||
328 | break; | ||
329 | default: | ||
330 | printk ("FLOGI failed for %s with status %d\n", fc->name, status); | ||
331 | /* Do some sort of error recovery here */ | ||
332 | break; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | void fcp_register(fc_channel *fc, u8 type, int unregister) | ||
337 | { | ||
338 | int size, i; | ||
339 | int slots = (fc->can_queue * 3) >> 1; | ||
340 | |||
341 | FCND(("Going to %sregister\n", unregister ? "un" : "")) | ||
342 | |||
343 | if (type == TYPE_SCSI_FCP) { | ||
344 | if (!unregister) { | ||
345 | fc->scsi_cmd_pool = (fcp_cmd *) | ||
346 | dma_alloc_consistent (fc->dev, | ||
347 | slots * (sizeof (fcp_cmd) + fc->rsp_size), | ||
348 | &fc->dma_scsi_cmd); | ||
349 | fc->scsi_rsp_pool = (char *)(fc->scsi_cmd_pool + slots); | ||
350 | fc->dma_scsi_rsp = fc->dma_scsi_cmd + slots * sizeof (fcp_cmd); | ||
351 | fc->scsi_bitmap_end = (slots + 63) & ~63; | ||
352 | size = fc->scsi_bitmap_end / 8; | ||
353 | fc->scsi_bitmap = kzalloc (size, GFP_KERNEL); | ||
354 | set_bit (0, fc->scsi_bitmap); | ||
355 | for (i = fc->can_queue; i < fc->scsi_bitmap_end; i++) | ||
356 | set_bit (i, fc->scsi_bitmap); | ||
357 | fc->scsi_free = fc->can_queue; | ||
358 | fc->cmd_slots = kzalloc(slots * sizeof(fcp_cmnd*), GFP_KERNEL); | ||
359 | fc->abort_count = 0; | ||
360 | } else { | ||
361 | fc->scsi_name[0] = 0; | ||
362 | kfree (fc->scsi_bitmap); | ||
363 | kfree (fc->cmd_slots); | ||
364 | FCND(("Unregistering\n")); | ||
365 | #if 0 | ||
366 | if (fc->rst_pkt) { | ||
367 | if (fc->rst_pkt->eh_state == SCSI_STATE_UNUSED) | ||
368 | kfree(fc->rst_pkt); | ||
369 | else { | ||
370 | /* Can't happen. Some memory would be lost. */ | ||
371 | printk("FC: Reset in progress. Now?!"); | ||
372 | } | ||
373 | } | ||
374 | #endif | ||
375 | FCND(("Unregistered\n")); | ||
376 | } | ||
377 | } else | ||
378 | printk ("FC: %segistering unknown type %02x\n", unregister ? "Unr" : "R", type); | ||
379 | } | ||
380 | |||
381 | static void fcp_scsi_done(struct scsi_cmnd *SCpnt); | ||
382 | |||
383 | static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hdr *fch) | ||
384 | { | ||
385 | fcp_cmnd *fcmd; | ||
386 | fcp_rsp *rsp; | ||
387 | int host_status; | ||
388 | struct scsi_cmnd *SCpnt; | ||
389 | int sense_len; | ||
390 | int rsp_status; | ||
391 | |||
392 | fcmd = fc->cmd_slots[token]; | ||
393 | if (!fcmd) return; | ||
394 | rsp = (fcp_rsp *) (fc->scsi_rsp_pool + fc->rsp_size * token); | ||
395 | SCpnt = SC_FCMND(fcmd); | ||
396 | |||
397 | if (SCpnt->done != fcp_scsi_done) | ||
398 | return; | ||
399 | |||
400 | rsp_status = rsp->fcp_status; | ||
401 | FCD(("rsp_status %08x status %08x\n", rsp_status, status)) | ||
402 | switch (status) { | ||
403 | case FC_STATUS_OK: | ||
404 | host_status=DID_OK; | ||
405 | |||
406 | if (rsp_status & FCP_STATUS_RESID) { | ||
407 | #ifdef FCDEBUG | ||
408 | FCD(("Resid %d\n", rsp->fcp_resid)) | ||
409 | { | ||
410 | fcp_cmd *cmd = fc->scsi_cmd_pool + token; | ||
411 | int i; | ||
412 | |||
413 | printk ("Command "); | ||
414 | for (i = 0; i < sizeof(fcp_cmd); i+=4) | ||
415 | printk ("%08x ", *(u32 *)(((char *)cmd)+i)); | ||
416 | printk ("\nResponse "); | ||
417 | for (i = 0; i < fc->rsp_size; i+=4) | ||
418 | printk ("%08x ", *(u32 *)(((char *)rsp)+i)); | ||
419 | printk ("\n"); | ||
420 | } | ||
421 | #endif | ||
422 | } | ||
423 | |||
424 | if (rsp_status & FCP_STATUS_SENSE_LEN) { | ||
425 | sense_len = rsp->fcp_sense_len; | ||
426 | if (sense_len > sizeof(SCpnt->sense_buffer)) sense_len = sizeof(SCpnt->sense_buffer); | ||
427 | memcpy(SCpnt->sense_buffer, ((char *)(rsp+1)), sense_len); | ||
428 | } | ||
429 | |||
430 | if (fcmd->data) | ||
431 | dma_unmap_sg(fc->dev, scsi_sglist(SCpnt), | ||
432 | scsi_sg_count(SCpnt), | ||
433 | SCpnt->sc_data_direction); | ||
434 | break; | ||
435 | default: | ||
436 | host_status=DID_ERROR; /* FIXME */ | ||
437 | FCD(("Wrong FC status %d for token %d\n", status, token)) | ||
438 | break; | ||
439 | } | ||
440 | |||
441 | if (status_byte(rsp_status) == QUEUE_FULL) { | ||
442 | printk ("%s: (%d,%d) Received rsp_status 0x%x\n", fc->name, SCpnt->device->channel, SCpnt->device->id, rsp_status); | ||
443 | } | ||
444 | |||
445 | SCpnt->result = (host_status << 16) | (rsp_status & 0xff); | ||
446 | #ifdef FCDEBUG | ||
447 | if (host_status || SCpnt->result || rsp_status) printk("FC: host_status %d, packet status %d\n", | ||
448 | host_status, SCpnt->result); | ||
449 | #endif | ||
450 | SCpnt->done = fcmd->done; | ||
451 | fcmd->done=NULL; | ||
452 | clear_bit(token, fc->scsi_bitmap); | ||
453 | fc->scsi_free++; | ||
454 | FCD(("Calling scsi_done with %08x\n", SCpnt->result)) | ||
455 | SCpnt->scsi_done(SCpnt); | ||
456 | } | ||
457 | |||
458 | void fcp_receive_solicited(fc_channel *fc, int proto, int token, int status, fc_hdr *fch) | ||
459 | { | ||
460 | int magic; | ||
461 | FCD(("receive_solicited %d %d %d\n", proto, token, status)) | ||
462 | switch (proto) { | ||
463 | case TYPE_SCSI_FCP: | ||
464 | fcp_scsi_receive(fc, token, status, fch); break; | ||
465 | case TYPE_EXTENDED_LS: | ||
466 | case PROTO_REPORT_AL_MAP: | ||
467 | magic = 0; | ||
468 | if (fc->ls) | ||
469 | magic = ((ls *)(fc->ls))->magic; | ||
470 | if (magic == LSMAGIC) { | ||
471 | ls *l = (ls *)fc->ls; | ||
472 | int i = (token >= l->count) ? token - l->count : token; | ||
473 | |||
474 | /* Let's be sure */ | ||
475 | if ((unsigned)i < l->count && l->fcmds[i].fc == fc) { | ||
476 | if (proto == TYPE_EXTENDED_LS) | ||
477 | fcp_login_done(fc, token, status); | ||
478 | else | ||
479 | fcp_report_map_done(fc, token, status); | ||
480 | break; | ||
481 | } | ||
482 | } | ||
483 | FCD(("fc %p fc->ls %p fc->cmd_slots %p\n", fc, fc->ls, fc->cmd_slots)) | ||
484 | if (proto == TYPE_EXTENDED_LS && !fc->ls && fc->cmd_slots) { | ||
485 | fcp_cmnd *fcmd; | ||
486 | |||
487 | fcmd = fc->cmd_slots[token]; | ||
488 | if (fcmd && fcmd->ls && ((ls *)(fcmd->ls))->magic == LSEMAGIC) { | ||
489 | lse *l = (lse *)fcmd->ls; | ||
490 | |||
491 | l->status = status; | ||
492 | up (&l->sem); | ||
493 | } | ||
494 | } | ||
495 | break; | ||
496 | case PROTO_OFFLINE: | ||
497 | if (fc->ls && ((lso *)(fc->ls))->magic == LSOMAGIC) { | ||
498 | lso *l = (lso *)fc->ls; | ||
499 | |||
500 | if ((unsigned)token < l->count && l->fcmds[token].fc == fc) { | ||
501 | /* Wow, OFFLINE response arrived :) */ | ||
502 | FCD(("OFFLINE Response arrived\n")) | ||
503 | fc->state = FC_STATE_OFFLINE; | ||
504 | if (atomic_dec_and_test (&l->todo)) | ||
505 | up(&l->sem); | ||
506 | } | ||
507 | } | ||
508 | break; | ||
509 | |||
510 | default: | ||
511 | break; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | void fcp_state_change(fc_channel *fc, int state) | ||
516 | { | ||
517 | FCD(("state_change %d %d\n", state, fc->state)) | ||
518 | if (state == FC_STATE_ONLINE && fc->state == FC_STATE_MAYBEOFFLINE) | ||
519 | fc->state = FC_STATE_UNINITED; | ||
520 | else if (state == FC_STATE_ONLINE) | ||
521 | printk (KERN_WARNING "%s: state change to ONLINE\n", fc->name); | ||
522 | else | ||
523 | printk (KERN_ERR "%s: state change to OFFLINE\n", fc->name); | ||
524 | } | ||
525 | |||
526 | int fcp_initialize(fc_channel *fcchain, int count) | ||
527 | { | ||
528 | fc_channel *fc; | ||
529 | fcp_cmnd *fcmd; | ||
530 | int i, retry, ret; | ||
531 | ls *l; | ||
532 | |||
533 | FCND(("fcp_inititialize %08lx\n", (long)fcp_init)) | ||
534 | FCND(("fc_channels %08lx\n", (long)fc_channels)) | ||
535 | FCND((" SID %d DID %d\n", fcchain->sid, fcchain->did)) | ||
536 | l = kzalloc(sizeof (ls) + count, GFP_KERNEL); | ||
537 | if (!l) { | ||
538 | printk ("FC: Cannot allocate memory for initialization\n"); | ||
539 | return -ENOMEM; | ||
540 | } | ||
541 | l->magic = LSMAGIC; | ||
542 | l->count = count; | ||
543 | FCND(("FCP Init for %d channels\n", count)) | ||
544 | init_MUTEX_LOCKED(&l->sem); | ||
545 | init_timer(&l->timer); | ||
546 | l->timer.function = fcp_login_timeout; | ||
547 | l->timer.data = (unsigned long)l; | ||
548 | atomic_set (&l->todo, count); | ||
549 | l->logi = kzalloc (count * 3 * sizeof(logi), GFP_KERNEL); | ||
550 | l->fcmds = kzalloc (count * sizeof(fcp_cmnd), GFP_KERNEL); | ||
551 | if (!l->logi || !l->fcmds) { | ||
552 | kfree (l->logi); | ||
553 | kfree (l->fcmds); | ||
554 | kfree (l); | ||
555 | printk ("FC: Cannot allocate DMA memory for initialization\n"); | ||
556 | return -ENOMEM; | ||
557 | } | ||
558 | for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { | ||
559 | fc->state = FC_STATE_UNINITED; | ||
560 | fc->rst_pkt = NULL; /* kmalloc when first used */ | ||
561 | } | ||
562 | /* First try if we are in a AL topology */ | ||
563 | FCND(("Initializing REPORT_MAP packets\n")) | ||
564 | for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { | ||
565 | fcmd = l->fcmds + i; | ||
566 | fc->login = fcmd; | ||
567 | fc->ls = (void *)l; | ||
568 | /* Assumes sizeof(fc_al_posmap) < 3 * sizeof(logi), which is true */ | ||
569 | fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi), | ||
570 | DMA_BIDIRECTIONAL); | ||
571 | fcmd->proto = PROTO_REPORT_AL_MAP; | ||
572 | fcmd->token = i; | ||
573 | fcmd->fc = fc; | ||
574 | } | ||
575 | for (retry = 0; retry < 8; retry++) { | ||
576 | int nqueued = 0; | ||
577 | FCND(("Sending REPORT_MAP/FLOGI/PLOGI packets\n")) | ||
578 | for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { | ||
579 | if (fc->state == FC_STATE_ONLINE || fc->state == FC_STATE_OFFLINE) | ||
580 | continue; | ||
581 | disable_irq(fc->irq); | ||
582 | if (fc->state == FC_STATE_MAYBEOFFLINE) { | ||
583 | if (!l->grace[i]) { | ||
584 | l->grace[i]++; | ||
585 | FCD(("Grace\n")) | ||
586 | } else { | ||
587 | fc->state = FC_STATE_OFFLINE; | ||
588 | enable_irq(fc->irq); | ||
589 | dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), DMA_BIDIRECTIONAL); | ||
590 | if (atomic_dec_and_test (&l->todo)) | ||
591 | goto all_done; | ||
592 | } | ||
593 | } | ||
594 | ret = fc->hw_enque (fc, fc->login); | ||
595 | enable_irq(fc->irq); | ||
596 | if (!ret) { | ||
597 | nqueued++; | ||
598 | continue; | ||
599 | } | ||
600 | if (ret == -ENOSYS && fc->login->proto == PROTO_REPORT_AL_MAP) { | ||
601 | /* Oh yes, this card handles Point-to-Point only, so let's try that. */ | ||
602 | fc_hdr *fch; | ||
603 | |||
604 | FCD(("SID %d DID %d\n", fc->sid, fc->did)) | ||
605 | fcmd = l->fcmds + i; | ||
606 | dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi), DMA_BIDIRECTIONAL); | ||
607 | fch = &fcmd->fch; | ||
608 | FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT); | ||
609 | FILL_FCHDR_SID(fch, 0); | ||
610 | FILL_FCHDR_TYPE_FCTL(fch, TYPE_EXTENDED_LS, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); | ||
611 | FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); | ||
612 | FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); | ||
613 | fch->param = 0; | ||
614 | l->logi [3 * i].code = LS_FLOGI; | ||
615 | fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi), DMA_BIDIRECTIONAL); | ||
616 | fcmd->rsp = fcmd->cmd + sizeof(logi); | ||
617 | fcmd->cmdlen = sizeof(logi); | ||
618 | fcmd->rsplen = sizeof(logi); | ||
619 | fcmd->data = (dma_addr_t)NULL; | ||
620 | fcmd->class = FC_CLASS_SIMPLE; | ||
621 | fcmd->proto = TYPE_EXTENDED_LS; | ||
622 | } else | ||
623 | printk ("FC: Cannot enque FLOGI/REPORT_MAP packet on %s\n", fc->name); | ||
624 | } | ||
625 | |||
626 | if (nqueued) { | ||
627 | l->timer.expires = jiffies + 5 * HZ; | ||
628 | add_timer(&l->timer); | ||
629 | |||
630 | down(&l->sem); | ||
631 | if (!atomic_read(&l->todo)) { | ||
632 | FCND(("All channels answered in time\n")) | ||
633 | break; /* All fc channels have answered us */ | ||
634 | } | ||
635 | } | ||
636 | } | ||
637 | all_done: | ||
638 | for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { | ||
639 | fc->ls = NULL; | ||
640 | switch (fc->state) { | ||
641 | case FC_STATE_ONLINE: break; | ||
642 | case FC_STATE_OFFLINE: break; | ||
643 | default: dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), DMA_BIDIRECTIONAL); | ||
644 | break; | ||
645 | } | ||
646 | } | ||
647 | del_timer(&l->timer); | ||
648 | kfree (l->logi); | ||
649 | kfree (l->fcmds); | ||
650 | kfree (l); | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | int fcp_forceoffline(fc_channel *fcchain, int count) | ||
655 | { | ||
656 | fc_channel *fc; | ||
657 | fcp_cmnd *fcmd; | ||
658 | int i, ret; | ||
659 | lso l; | ||
660 | |||
661 | memset (&l, 0, sizeof(lso)); | ||
662 | l.count = count; | ||
663 | l.magic = LSOMAGIC; | ||
664 | FCND(("FCP Force Offline for %d channels\n", count)) | ||
665 | init_MUTEX_LOCKED(&l.sem); | ||
666 | init_timer(&l.timer); | ||
667 | l.timer.function = fcp_login_timeout; | ||
668 | l.timer.data = (unsigned long)&l; | ||
669 | atomic_set (&l.todo, count); | ||
670 | l.fcmds = kzalloc (count * sizeof(fcp_cmnd), GFP_KERNEL); | ||
671 | if (!l.fcmds) { | ||
672 | printk ("FC: Cannot allocate memory for forcing offline\n"); | ||
673 | return -ENOMEM; | ||
674 | } | ||
675 | FCND(("Initializing OFFLINE packets\n")) | ||
676 | for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { | ||
677 | fc->state = FC_STATE_UNINITED; | ||
678 | fcmd = l.fcmds + i; | ||
679 | fc->login = fcmd; | ||
680 | fc->ls = (void *)&l; | ||
681 | fcmd->did = fc->did; | ||
682 | fcmd->class = FC_CLASS_OFFLINE; | ||
683 | fcmd->proto = PROTO_OFFLINE; | ||
684 | fcmd->token = i; | ||
685 | fcmd->fc = fc; | ||
686 | disable_irq(fc->irq); | ||
687 | ret = fc->hw_enque (fc, fc->login); | ||
688 | enable_irq(fc->irq); | ||
689 | if (ret) printk ("FC: Cannot enque OFFLINE packet on %s\n", fc->name); | ||
690 | } | ||
691 | |||
692 | l.timer.expires = jiffies + 5 * HZ; | ||
693 | add_timer(&l.timer); | ||
694 | down(&l.sem); | ||
695 | del_timer(&l.timer); | ||
696 | |||
697 | for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) | ||
698 | fc->ls = NULL; | ||
699 | kfree (l.fcmds); | ||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | int fcp_init(fc_channel *fcchain) | ||
704 | { | ||
705 | fc_channel *fc; | ||
706 | int count=0; | ||
707 | int ret; | ||
708 | |||
709 | for (fc = fcchain; fc; fc = fc->next) { | ||
710 | fc->fcp_register = fcp_register; | ||
711 | count++; | ||
712 | } | ||
713 | |||
714 | ret = fcp_initialize (fcchain, count); | ||
715 | if (ret) | ||
716 | return ret; | ||
717 | |||
718 | if (!fc_channels) | ||
719 | fc_channels = fcchain; | ||
720 | else { | ||
721 | for (fc = fc_channels; fc->next; fc = fc->next); | ||
722 | fc->next = fcchain; | ||
723 | } | ||
724 | return ret; | ||
725 | } | ||
726 | |||
727 | void fcp_release(fc_channel *fcchain, int count) /* count must > 0 */ | ||
728 | { | ||
729 | fc_channel *fc; | ||
730 | fc_channel *fcx; | ||
731 | |||
732 | for (fc = fcchain; --count && fc->next; fc = fc->next); | ||
733 | if (count) { | ||
734 | printk("FC: nothing to release\n"); | ||
735 | return; | ||
736 | } | ||
737 | |||
738 | if (fc_channels == fcchain) | ||
739 | fc_channels = fc->next; | ||
740 | else { | ||
741 | for (fcx = fc_channels; fcx->next != fcchain; fcx = fcx->next); | ||
742 | fcx->next = fc->next; | ||
743 | } | ||
744 | fc->next = NULL; | ||
745 | |||
746 | /* | ||
747 | * We've just grabbed fcchain out of the fc_channel list | ||
748 | * and zero-terminated it, while destroying the count. | ||
749 | * | ||
750 | * Freeing the fc's is the low level driver's responsibility. | ||
751 | */ | ||
752 | } | ||
753 | |||
754 | |||
755 | static void fcp_scsi_done(struct scsi_cmnd *SCpnt) | ||
756 | { | ||
757 | if (FCP_CMND(SCpnt)->done) | ||
758 | FCP_CMND(SCpnt)->done(SCpnt); | ||
759 | } | ||
760 | |||
761 | static int fcp_scsi_queue_it(fc_channel *fc, struct scsi_cmnd *SCpnt, | ||
762 | fcp_cmnd *fcmd, int prepare) | ||
763 | { | ||
764 | long i; | ||
765 | fcp_cmd *cmd; | ||
766 | u32 fcp_cntl; | ||
767 | if (prepare) { | ||
768 | i = find_first_zero_bit (fc->scsi_bitmap, fc->scsi_bitmap_end); | ||
769 | set_bit (i, fc->scsi_bitmap); | ||
770 | fcmd->token = i; | ||
771 | cmd = fc->scsi_cmd_pool + i; | ||
772 | |||
773 | if (fc->encode_addr (SCpnt, cmd->fcp_addr, fc, fcmd)) { | ||
774 | /* Invalid channel/id/lun and couldn't map it into fcp_addr */ | ||
775 | clear_bit (i, fc->scsi_bitmap); | ||
776 | SCpnt->result = (DID_BAD_TARGET << 16); | ||
777 | SCpnt->scsi_done(SCpnt); | ||
778 | return 0; | ||
779 | } | ||
780 | fc->scsi_free--; | ||
781 | fc->cmd_slots[fcmd->token] = fcmd; | ||
782 | |||
783 | if (SCpnt->device->tagged_supported) { | ||
784 | if (jiffies - fc->ages[SCpnt->device->channel * fc->targets + SCpnt->device->id] > (5 * 60 * HZ)) { | ||
785 | fc->ages[SCpnt->device->channel * fc->targets + SCpnt->device->id] = jiffies; | ||
786 | fcp_cntl = FCP_CNTL_QTYPE_ORDERED; | ||
787 | } else | ||
788 | fcp_cntl = FCP_CNTL_QTYPE_SIMPLE; | ||
789 | } else | ||
790 | fcp_cntl = FCP_CNTL_QTYPE_UNTAGGED; | ||
791 | |||
792 | if (!scsi_bufflen(SCpnt)) { | ||
793 | cmd->fcp_cntl = fcp_cntl; | ||
794 | fcmd->data = (dma_addr_t)NULL; | ||
795 | } else { | ||
796 | struct scatterlist *sg; | ||
797 | int nents; | ||
798 | |||
799 | switch (SCpnt->cmnd[0]) { | ||
800 | case WRITE_6: | ||
801 | case WRITE_10: | ||
802 | case WRITE_12: | ||
803 | cmd->fcp_cntl = (FCP_CNTL_WRITE | fcp_cntl); break; | ||
804 | default: | ||
805 | cmd->fcp_cntl = (FCP_CNTL_READ | fcp_cntl); break; | ||
806 | } | ||
807 | |||
808 | sg = scsi_sglist(SCpnt); | ||
809 | nents = dma_map_sg(fc->dev, sg, scsi_sg_count(SCpnt), | ||
810 | SCpnt->sc_data_direction); | ||
811 | fcmd->data = sg_dma_address(sg); | ||
812 | cmd->fcp_data_len = sg_dma_len(sg); | ||
813 | } | ||
814 | memcpy (cmd->fcp_cdb, SCpnt->cmnd, SCpnt->cmd_len); | ||
815 | memset (cmd->fcp_cdb+SCpnt->cmd_len, 0, sizeof(cmd->fcp_cdb)-SCpnt->cmd_len); | ||
816 | FCD(("XXX: %04x.%04x.%04x.%04x - %08x%08x%08x\n", cmd->fcp_addr[0], cmd->fcp_addr[1], cmd->fcp_addr[2], cmd->fcp_addr[3], *(u32 *)SCpnt->cmnd, *(u32 *)(SCpnt->cmnd+4), *(u32 *)(SCpnt->cmnd+8))) | ||
817 | } | ||
818 | FCD(("Trying to enque %p\n", fcmd)) | ||
819 | if (!fc->scsi_que) { | ||
820 | if (!fc->hw_enque (fc, fcmd)) { | ||
821 | FCD(("hw_enque succeeded for %p\n", fcmd)) | ||
822 | return 0; | ||
823 | } | ||
824 | } | ||
825 | FCD(("Putting into que1 %p\n", fcmd)) | ||
826 | fcp_scsi_insert_queue (fc, fcmd); | ||
827 | return 0; | ||
828 | } | ||
829 | |||
830 | int fcp_scsi_queuecommand(struct scsi_cmnd *SCpnt, | ||
831 | void (* done)(struct scsi_cmnd *)) | ||
832 | { | ||
833 | fcp_cmnd *fcmd = FCP_CMND(SCpnt); | ||
834 | fc_channel *fc = FC_SCMND(SCpnt); | ||
835 | |||
836 | FCD(("Entering SCSI queuecommand %p\n", fcmd)) | ||
837 | if (SCpnt->done != fcp_scsi_done) { | ||
838 | fcmd->done = SCpnt->done; | ||
839 | SCpnt->done = fcp_scsi_done; | ||
840 | SCpnt->scsi_done = done; | ||
841 | fcmd->proto = TYPE_SCSI_FCP; | ||
842 | if (!fc->scsi_free) { | ||
843 | FCD(("FC: !scsi_free, putting cmd on ML queue\n")) | ||
844 | #if (FCP_SCSI_USE_NEW_EH_CODE == 0) | ||
845 | printk("fcp_scsi_queue_command: queue full, losing cmd, bad\n"); | ||
846 | #endif | ||
847 | return 1; | ||
848 | } | ||
849 | return fcp_scsi_queue_it(fc, SCpnt, fcmd, 1); | ||
850 | } | ||
851 | return fcp_scsi_queue_it(fc, SCpnt, fcmd, 0); | ||
852 | } | ||
853 | |||
854 | void fcp_queue_empty(fc_channel *fc) | ||
855 | { | ||
856 | fcp_cmnd *fcmd; | ||
857 | |||
858 | FCD(("Queue empty\n")) | ||
859 | while ((fcmd = fc->scsi_que)) { | ||
860 | /* The hw told us we can try again queue some packet */ | ||
861 | if (fc->hw_enque (fc, fcmd)) | ||
862 | break; | ||
863 | fcp_scsi_remove_queue (fc, fcmd); | ||
864 | } | ||
865 | } | ||
866 | |||
867 | int fcp_scsi_abort(struct scsi_cmnd *SCpnt) | ||
868 | { | ||
869 | /* Internal bookkeeping only. Lose 1 cmd_slots slot. */ | ||
870 | fcp_cmnd *fcmd = FCP_CMND(SCpnt); | ||
871 | fc_channel *fc = FC_SCMND(SCpnt); | ||
872 | |||
873 | /* | ||
874 | * We react to abort requests by simply forgetting | ||
875 | * about the command and pretending everything's sweet. | ||
876 | * This may or may not be silly. We can't, however, | ||
877 | * immediately reuse the command's cmd_slots slot, | ||
878 | * as its result may arrive later and we cannot | ||
879 | * check whether it is the aborted one, can't we? | ||
880 | * | ||
881 | * Therefore, after the first few aborts are done, | ||
882 | * we tell the scsi error handler to do something clever. | ||
883 | * It will eventually call host reset, refreshing | ||
884 | * cmd_slots for us. | ||
885 | * | ||
886 | * There is a theoretical chance that we sometimes allow | ||
887 | * more than can_queue packets to the jungle this way, | ||
888 | * but the worst outcome possible is a series of | ||
889 | * more aborts and eventually the dev_reset catharsis. | ||
890 | */ | ||
891 | |||
892 | if (++fc->abort_count < (fc->can_queue >> 1)) { | ||
893 | SCpnt->result = DID_ABORT; | ||
894 | fcmd->done(SCpnt); | ||
895 | printk("FC: soft abort\n"); | ||
896 | return SUCCESS; | ||
897 | } else { | ||
898 | printk("FC: hard abort refused\n"); | ||
899 | return FAILED; | ||
900 | } | ||
901 | } | ||
902 | |||
903 | #if 0 | ||
904 | void fcp_scsi_reset_done(struct scsi_cmnd *SCpnt) | ||
905 | { | ||
906 | fc_channel *fc = FC_SCMND(SCpnt); | ||
907 | |||
908 | fc->rst_pkt->eh_state = SCSI_STATE_FINISHED; | ||
909 | up(fc->rst_pkt->device->host->eh_action); | ||
910 | } | ||
911 | #endif | ||
912 | |||
913 | #define FCP_RESET_TIMEOUT (2*HZ) | ||
914 | |||
915 | int fcp_scsi_dev_reset(struct scsi_cmnd *SCpnt) | ||
916 | { | ||
917 | #if 0 /* broken junk, but if davem wants to compile this driver, let him.. */ | ||
918 | unsigned long flags; | ||
919 | fcp_cmd *cmd; | ||
920 | fcp_cmnd *fcmd; | ||
921 | fc_channel *fc = FC_SCMND(SCpnt); | ||
922 | DECLARE_MUTEX_LOCKED(sem); | ||
923 | |||
924 | if (!fc->rst_pkt) { | ||
925 | fc->rst_pkt = kmalloc(sizeof(SCpnt), GFP_KERNEL); | ||
926 | if (!fc->rst_pkt) return FAILED; | ||
927 | |||
928 | fcmd = FCP_CMND(fc->rst_pkt); | ||
929 | |||
930 | |||
931 | fcmd->token = 0; | ||
932 | cmd = fc->scsi_cmd_pool + 0; | ||
933 | FCD(("Preparing rst packet\n")) | ||
934 | fc->encode_addr (SCpnt, cmd->fcp_addr, fc, fcmd); | ||
935 | fc->rst_pkt->device = SCpnt->device; | ||
936 | fc->rst_pkt->cmd_len = 0; | ||
937 | |||
938 | fc->cmd_slots[0] = fcmd; | ||
939 | |||
940 | cmd->fcp_cntl = FCP_CNTL_QTYPE_ORDERED | FCP_CNTL_RESET; | ||
941 | fcmd->data = (dma_addr_t)NULL; | ||
942 | fcmd->proto = TYPE_SCSI_FCP; | ||
943 | |||
944 | memcpy (cmd->fcp_cdb, SCpnt->cmnd, SCpnt->cmd_len); | ||
945 | memset (cmd->fcp_cdb+SCpnt->cmd_len, 0, sizeof(cmd->fcp_cdb)-SCpnt->cmd_len); | ||
946 | FCD(("XXX: %04x.%04x.%04x.%04x - %08x%08x%08x\n", cmd->fcp_addr[0], cmd->fcp_addr[1], cmd->fcp_addr[2], cmd->fcp_addr[3], *(u32 *)SCpnt->cmnd, *(u32 *)(SCpnt->cmnd+4), *(u32 *)(SCpnt->cmnd+8))) | ||
947 | } else { | ||
948 | fcmd = FCP_CMND(fc->rst_pkt); | ||
949 | if (fc->rst_pkt->eh_state == SCSI_STATE_QUEUED) | ||
950 | return FAILED; /* or SUCCESS. Only these */ | ||
951 | } | ||
952 | fc->rst_pkt->done = NULL; | ||
953 | |||
954 | |||
955 | fc->rst_pkt->eh_state = SCSI_STATE_QUEUED; | ||
956 | init_timer(&fc->rst_pkt->eh_timeout); | ||
957 | fc->rst_pkt->eh_timeout.data = (unsigned long) fc->rst_pkt; | ||
958 | fc->rst_pkt->eh_timeout.expires = jiffies + FCP_RESET_TIMEOUT; | ||
959 | fc->rst_pkt->eh_timeout.function = (void (*)(unsigned long))fcp_scsi_reset_done; | ||
960 | |||
961 | add_timer(&fc->rst_pkt->eh_timeout); | ||
962 | |||
963 | /* | ||
964 | * Set up the semaphore so we wait for the command to complete. | ||
965 | */ | ||
966 | |||
967 | fc->rst_pkt->device->host->eh_action = &sem; | ||
968 | |||
969 | fc->rst_pkt->done = fcp_scsi_reset_done; | ||
970 | |||
971 | spin_lock_irqsave(SCpnt->device->host->host_lock, flags); | ||
972 | fcp_scsi_queue_it(fc, fc->rst_pkt, fcmd, 0); | ||
973 | spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags); | ||
974 | |||
975 | down(&sem); | ||
976 | |||
977 | fc->rst_pkt->device->host->eh_action = NULL; | ||
978 | del_timer(&fc->rst_pkt->eh_timeout); | ||
979 | |||
980 | /* | ||
981 | * See if timeout. If so, tell the host to forget about it. | ||
982 | * In other words, we don't want a callback any more. | ||
983 | */ | ||
984 | if (fc->rst_pkt->eh_state == SCSI_STATE_TIMEOUT ) { | ||
985 | fc->rst_pkt->eh_state = SCSI_STATE_UNUSED; | ||
986 | return FAILED; | ||
987 | } | ||
988 | fc->rst_pkt->eh_state = SCSI_STATE_UNUSED; | ||
989 | #endif | ||
990 | return SUCCESS; | ||
991 | } | ||
992 | |||
993 | static int __fcp_scsi_host_reset(struct scsi_cmnd *SCpnt) | ||
994 | { | ||
995 | fc_channel *fc = FC_SCMND(SCpnt); | ||
996 | fcp_cmnd *fcmd = FCP_CMND(SCpnt); | ||
997 | int i; | ||
998 | |||
999 | printk ("FC: host reset\n"); | ||
1000 | |||
1001 | for (i=0; i < fc->can_queue; i++) { | ||
1002 | if (fc->cmd_slots[i] && SCpnt->result != DID_ABORT) { | ||
1003 | SCpnt->result = DID_RESET; | ||
1004 | fcmd->done(SCpnt); | ||
1005 | fc->cmd_slots[i] = NULL; | ||
1006 | } | ||
1007 | } | ||
1008 | fc->reset(fc); | ||
1009 | fc->abort_count = 0; | ||
1010 | if (fcp_initialize(fc, 1)) return SUCCESS; | ||
1011 | else return FAILED; | ||
1012 | } | ||
1013 | |||
1014 | int fcp_scsi_host_reset(struct scsi_cmnd *SCpnt) | ||
1015 | { | ||
1016 | unsigned long flags; | ||
1017 | int rc; | ||
1018 | |||
1019 | spin_lock_irqsave(SCpnt->device->host->host_lock, flags); | ||
1020 | rc = __fcp_scsi_host_reset(SCpnt); | ||
1021 | spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags); | ||
1022 | |||
1023 | return rc; | ||
1024 | } | ||
1025 | |||
1026 | static int fcp_els_queue_it(fc_channel *fc, fcp_cmnd *fcmd) | ||
1027 | { | ||
1028 | long i; | ||
1029 | |||
1030 | i = find_first_zero_bit (fc->scsi_bitmap, fc->scsi_bitmap_end); | ||
1031 | set_bit (i, fc->scsi_bitmap); | ||
1032 | fcmd->token = i; | ||
1033 | fc->scsi_free--; | ||
1034 | fc->cmd_slots[fcmd->token] = fcmd; | ||
1035 | return fcp_scsi_queue_it(fc, NULL, fcmd, 0); | ||
1036 | } | ||
1037 | |||
1038 | static int fc_do_els(fc_channel *fc, unsigned int alpa, void *data, int len) | ||
1039 | { | ||
1040 | fcp_cmnd _fcmd, *fcmd; | ||
1041 | fc_hdr *fch; | ||
1042 | lse l; | ||
1043 | int i; | ||
1044 | |||
1045 | fcmd = &_fcmd; | ||
1046 | memset(fcmd, 0, sizeof(fcp_cmnd)); | ||
1047 | FCD(("PLOGI SID %d DID %d\n", fc->sid, alpa)) | ||
1048 | fch = &fcmd->fch; | ||
1049 | FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, alpa); | ||
1050 | FILL_FCHDR_SID(fch, fc->sid); | ||
1051 | FILL_FCHDR_TYPE_FCTL(fch, TYPE_EXTENDED_LS, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); | ||
1052 | FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); | ||
1053 | FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); | ||
1054 | fch->param = 0; | ||
1055 | fcmd->cmd = dma_map_single (fc->dev, data, 2 * len, DMA_BIDIRECTIONAL); | ||
1056 | fcmd->rsp = fcmd->cmd + len; | ||
1057 | fcmd->cmdlen = len; | ||
1058 | fcmd->rsplen = len; | ||
1059 | fcmd->data = (dma_addr_t)NULL; | ||
1060 | fcmd->fc = fc; | ||
1061 | fcmd->class = FC_CLASS_SIMPLE; | ||
1062 | fcmd->proto = TYPE_EXTENDED_LS; | ||
1063 | |||
1064 | memset (&l, 0, sizeof(lse)); | ||
1065 | l.magic = LSEMAGIC; | ||
1066 | init_MUTEX_LOCKED(&l.sem); | ||
1067 | l.timer.function = fcp_login_timeout; | ||
1068 | l.timer.data = (unsigned long)&l; | ||
1069 | l.status = FC_STATUS_TIMED_OUT; | ||
1070 | fcmd->ls = (void *)&l; | ||
1071 | |||
1072 | disable_irq(fc->irq); | ||
1073 | fcp_els_queue_it(fc, fcmd); | ||
1074 | enable_irq(fc->irq); | ||
1075 | |||
1076 | for (i = 0;;) { | ||
1077 | l.timer.expires = jiffies + 5 * HZ; | ||
1078 | add_timer(&l.timer); | ||
1079 | down(&l.sem); | ||
1080 | del_timer(&l.timer); | ||
1081 | if (l.status != FC_STATUS_TIMED_OUT) break; | ||
1082 | if (++i == 3) break; | ||
1083 | disable_irq(fc->irq); | ||
1084 | fcp_scsi_queue_it(fc, NULL, fcmd, 0); | ||
1085 | enable_irq(fc->irq); | ||
1086 | } | ||
1087 | |||
1088 | clear_bit(fcmd->token, fc->scsi_bitmap); | ||
1089 | fc->scsi_free++; | ||
1090 | dma_unmap_single (fc->dev, fcmd->cmd, 2 * len, DMA_BIDIRECTIONAL); | ||
1091 | return l.status; | ||
1092 | } | ||
1093 | |||
1094 | int fc_do_plogi(fc_channel *fc, unsigned char alpa, fc_wwn *node, fc_wwn *nport) | ||
1095 | { | ||
1096 | logi *l; | ||
1097 | int status; | ||
1098 | |||
1099 | l = kzalloc(2 * sizeof(logi), GFP_KERNEL); | ||
1100 | if (!l) return -ENOMEM; | ||
1101 | l->code = LS_PLOGI; | ||
1102 | memcpy (&l->nport_wwn, &fc->wwn_nport, sizeof(fc_wwn)); | ||
1103 | memcpy (&l->node_wwn, &fc->wwn_node, sizeof(fc_wwn)); | ||
1104 | memcpy (&l->common, fc->common_svc, sizeof(common_svc_parm)); | ||
1105 | memcpy (&l->class1, fc->class_svcs, 3*sizeof(svc_parm)); | ||
1106 | status = fc_do_els(fc, alpa, l, sizeof(logi)); | ||
1107 | if (status == FC_STATUS_OK) { | ||
1108 | if (l[1].code == LS_ACC) { | ||
1109 | #ifdef FCDEBUG | ||
1110 | u32 *u = (u32 *)&l[1].nport_wwn; | ||
1111 | FCD(("AL-PA %02x: Port WWN %08x%08x Node WWN %08x%08x\n", alpa, | ||
1112 | u[0], u[1], u[2], u[3])) | ||
1113 | #endif | ||
1114 | memcpy(nport, &l[1].nport_wwn, sizeof(fc_wwn)); | ||
1115 | memcpy(node, &l[1].node_wwn, sizeof(fc_wwn)); | ||
1116 | } else | ||
1117 | status = FC_STATUS_BAD_RSP; | ||
1118 | } | ||
1119 | kfree(l); | ||
1120 | return status; | ||
1121 | } | ||
1122 | |||
1123 | typedef struct { | ||
1124 | unsigned int code; | ||
1125 | unsigned params[4]; | ||
1126 | } prli; | ||
1127 | |||
1128 | int fc_do_prli(fc_channel *fc, unsigned char alpa) | ||
1129 | { | ||
1130 | prli *p; | ||
1131 | int status; | ||
1132 | |||
1133 | p = kzalloc(2 * sizeof(prli), GFP_KERNEL); | ||
1134 | if (!p) return -ENOMEM; | ||
1135 | p->code = LS_PRLI; | ||
1136 | p->params[0] = 0x08002000; | ||
1137 | p->params[3] = 0x00000022; | ||
1138 | status = fc_do_els(fc, alpa, p, sizeof(prli)); | ||
1139 | if (status == FC_STATUS_OK && p[1].code != LS_PRLI_ACC && p[1].code != LS_ACC) | ||
1140 | status = FC_STATUS_BAD_RSP; | ||
1141 | kfree(p); | ||
1142 | return status; | ||
1143 | } | ||
1144 | |||
1145 | MODULE_LICENSE("GPL"); | ||
1146 | |||
diff --git a/drivers/fc4/fc.h b/drivers/fc4/fc.h deleted file mode 100644 index 13f89d4c8cb9..000000000000 --- a/drivers/fc4/fc.h +++ /dev/null | |||
@@ -1,230 +0,0 @@ | |||
1 | /* fc.h: Definitions for Fibre Channel Physical and Signaling Interface. | ||
2 | * | ||
3 | * Copyright (C) 1996-1997,1999 Jakub Jelinek (jj@ultra.linux.cz) | ||
4 | * | ||
5 | * Sources: | ||
6 | * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994 | ||
7 | * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995 | ||
8 | */ | ||
9 | |||
10 | #ifndef __FC_H | ||
11 | #define __FC_H | ||
12 | |||
13 | /* World Wide Name */ | ||
14 | #define NAAID_IEEE 1 | ||
15 | #define NAAID_IEEE_EXT 2 | ||
16 | #define NAAID_LOCAL 3 | ||
17 | #define NAAID_IP 4 | ||
18 | #define NAAID_IEEE_REG 5 | ||
19 | #define NAAID_IEEE_REG_EXT 6 | ||
20 | #define NAAID_CCITT 12 | ||
21 | #define NAAID_CCITT_GRP 14 | ||
22 | |||
23 | /* This is NAAID_IEEE_EXT scheme */ | ||
24 | typedef struct { | ||
25 | u32 naaid:4; | ||
26 | u32 nportid:12; | ||
27 | u32 hi:16; | ||
28 | u32 lo; | ||
29 | } fc_wwn; | ||
30 | |||
31 | /* Frame header for FC-PH frames */ | ||
32 | |||
33 | /* r_ctl field */ | ||
34 | #define R_CTL_DEVICE_DATA 0x00 /* FC4 Device_Data frame */ | ||
35 | #define R_CTL_EXTENDED_SVC 0x20 /* Extended Link_Data frame */ | ||
36 | #define R_CTL_FC4_SVC 0x30 /* FC4 Link_Data frame */ | ||
37 | #define R_CTL_VIDEO 0x40 /* Video_Data frame */ | ||
38 | #define R_CTL_BASIC_SVC 0x80 /* Basic Link_Data frame */ | ||
39 | #define R_CTL_LINK_CTL 0xc0 /* Link_Control frame */ | ||
40 | /* FC4 Device_Data frames */ | ||
41 | #define R_CTL_UNCATEGORIZED 0x00 | ||
42 | #define R_CTL_SOLICITED_DATA 0x01 | ||
43 | #define R_CTL_UNSOL_CONTROL 0x02 | ||
44 | #define R_CTL_SOLICITED_CONTROL 0x03 | ||
45 | #define R_CTL_UNSOL_DATA 0x04 | ||
46 | #define R_CTL_XFER_RDY 0x05 | ||
47 | #define R_CTL_COMMAND 0x06 | ||
48 | #define R_CTL_STATUS 0x07 | ||
49 | /* Basic Link_Data frames */ | ||
50 | #define R_CTL_LS_NOP 0x80 | ||
51 | #define R_CTL_LS_ABTS 0x81 | ||
52 | #define R_CTL_LS_RMC 0x82 | ||
53 | #define R_CTL_LS_BA_ACC 0x84 | ||
54 | #define R_CTL_LS_BA_RJT 0x85 | ||
55 | /* Extended Link_Data frames */ | ||
56 | #define R_CTL_ELS_REQ 0x22 | ||
57 | #define R_CTL_ELS_RSP 0x23 | ||
58 | /* Link_Control frames */ | ||
59 | #define R_CTL_ACK_1 0xc0 | ||
60 | #define R_CTL_ACK_N 0xc1 | ||
61 | #define R_CTL_P_RJT 0xc2 | ||
62 | #define R_CTL_F_RJT 0xc3 | ||
63 | #define R_CTL_P_BSY 0xc4 | ||
64 | #define R_CTL_F_BSY_DF 0xc5 | ||
65 | #define R_CTL_F_BSY_LC 0xc6 | ||
66 | #define R_CTL_LCR 0xc7 | ||
67 | |||
68 | /* type field */ | ||
69 | #define TYPE_BASIC_LS 0x00 | ||
70 | #define TYPE_EXTENDED_LS 0x01 | ||
71 | #define TYPE_IS8802 0x04 | ||
72 | #define TYPE_IS8802_SNAP 0x05 | ||
73 | #define TYPE_SCSI_FCP 0x08 | ||
74 | #define TYPE_SCSI_GPP 0x09 | ||
75 | #define TYPE_HIPP_FP 0x0a | ||
76 | #define TYPE_IPI3_MASTER 0x11 | ||
77 | #define TYPE_IPI3_SLAVE 0x12 | ||
78 | #define TYPE_IPI3_PEER 0x13 | ||
79 | |||
80 | /* f_ctl field */ | ||
81 | #define F_CTL_FILL_BYTES 0x000003 | ||
82 | #define F_CTL_XCHG_REASSEMBLE 0x000004 | ||
83 | #define F_CTL_RO_PRESENT 0x000008 | ||
84 | #define F_CTL_ABORT_SEQ 0x000030 | ||
85 | #define F_CTL_CONTINUE_SEQ 0x0000c0 | ||
86 | #define F_CTL_INVALIDATE_XID 0x004000 | ||
87 | #define F_CTL_XID_REASSIGNED 0x008000 | ||
88 | #define F_CTL_SEQ_INITIATIVE 0x010000 | ||
89 | #define F_CTL_CHAINED_SEQ 0x020000 | ||
90 | #define F_CTL_END_CONNECT 0x040000 | ||
91 | #define F_CTL_END_SEQ 0x080000 | ||
92 | #define F_CTL_LAST_SEQ 0x100000 | ||
93 | #define F_CTL_FIRST_SEQ 0x200000 | ||
94 | #define F_CTL_SEQ_CONTEXT 0x400000 | ||
95 | #define F_CTL_XCHG_CONTEXT 0x800000 | ||
96 | |||
97 | typedef struct { | ||
98 | u32 r_ctl:8, did:24; | ||
99 | u32 xxx1:8, sid:24; | ||
100 | u32 type:8, f_ctl:24; | ||
101 | u32 seq_id:8, df_ctl:8, seq_cnt:16; | ||
102 | u16 ox_id, rx_id; | ||
103 | u32 param; | ||
104 | } fc_hdr; | ||
105 | /* The following are ugly macros to make setup of this structure faster */ | ||
106 | #define FILL_FCHDR_RCTL_DID(fch, r_ctl, did) *(u32 *)(fch) = ((r_ctl) << 24) | (did); | ||
107 | #define FILL_FCHDR_SID(fch, sid) *((u32 *)(fch)+1) = (sid); | ||
108 | #define FILL_FCHDR_TYPE_FCTL(fch, type, f_ctl) *((u32 *)(fch)+2) = ((type) << 24) | (f_ctl); | ||
109 | #define FILL_FCHDR_SEQ_DF_SEQ(fch, seq_id, df_ctl, seq_cnt) *((u32 *)(fch)+3) = ((seq_id) << 24) | ((df_ctl) << 16) | (seq_cnt); | ||
110 | #define FILL_FCHDR_OXRX(fch, ox_id, rx_id) *((u32 *)(fch)+4) = ((ox_id) << 16) | (rx_id); | ||
111 | |||
112 | /* Well known addresses */ | ||
113 | #define FS_GENERAL_MULTICAST 0xfffff7 | ||
114 | #define FS_WELL_KNOWN_MULTICAST 0xfffff8 | ||
115 | #define FS_HUNT_GROUP 0xfffff9 | ||
116 | #define FS_MANAGEMENT_SERVER 0xfffffa | ||
117 | #define FS_TIME_SERVER 0xfffffb | ||
118 | #define FS_NAME_SERVER 0xfffffc | ||
119 | #define FS_FABRIC_CONTROLLER 0xfffffd | ||
120 | #define FS_FABRIC_F_PORT 0xfffffe | ||
121 | #define FS_BROADCAST 0xffffff | ||
122 | |||
123 | /* Reject frames */ | ||
124 | /* The param field should be cast to this structure */ | ||
125 | typedef struct { | ||
126 | u8 action; | ||
127 | u8 reason; | ||
128 | u8 xxx; | ||
129 | u8 vendor_unique; | ||
130 | } rjt_param; | ||
131 | |||
132 | /* Reject action codes */ | ||
133 | #define RJT_RETRY 0x01 | ||
134 | #define RJT_NONRETRY 0x02 | ||
135 | |||
136 | /* Reject reason codes */ | ||
137 | #define RJT_INVALID_DID 0x01 | ||
138 | #define RJT_INVALID_SID 0x02 | ||
139 | #define RJT_NPORT_NOT_AVAIL_TEMP 0x03 | ||
140 | #define RJT_NPORT_NOT_AVAIL_PERM 0x04 | ||
141 | #define RJT_CLASS_NOT_SUPPORTED 0x05 | ||
142 | #define RJT_DELIMITER_ERROR 0x06 | ||
143 | #define RJT_TYPE_NOT_SUPPORTED 0x07 | ||
144 | #define RJT_INVALID_LINK_CONTROL 0x08 | ||
145 | #define RJT_INVALID_R_CTL 0x09 | ||
146 | #define RJT_INVALID_F_CTL 0x0a | ||
147 | #define RJT_INVALID_OX_ID 0x0b | ||
148 | #define RJT_INVALID_RX_ID 0x0c | ||
149 | #define RJT_INVALID_SEQ_ID 0x0d | ||
150 | #define RJT_INVALID_DF_CTL 0x0e | ||
151 | #define RJT_INVALID_SEQ_CNT 0x0f | ||
152 | #define RJT_INVALID_PARAMETER 0x10 | ||
153 | #define RJT_EXCHANGE_ERROR 0x11 | ||
154 | #define RJT_PROTOCOL_ERROR 0x12 | ||
155 | #define RJT_INCORRECT_LENGTH 0x13 | ||
156 | #define RJT_UNEXPECTED_ACK 0x14 | ||
157 | #define RJT_UNEXPECTED_LINK_RESP 0x15 | ||
158 | #define RJT_LOGIN_REQUIRED 0x16 | ||
159 | #define RJT_EXCESSIVE_SEQUENCES 0x17 | ||
160 | #define RJT_CANT_ESTABLISH_EXCHANGE 0x18 | ||
161 | #define RJT_SECURITY_NOT_SUPPORTED 0x19 | ||
162 | #define RJT_FABRIC_NA 0x1a | ||
163 | #define RJT_VENDOR_UNIQUE 0xff | ||
164 | |||
165 | |||
166 | #define SP_F_PORT_LOGIN 0x10 | ||
167 | |||
168 | /* Extended SVC commands */ | ||
169 | #define LS_RJT 0x01000000 | ||
170 | #define LS_ACC 0x02000000 | ||
171 | #define LS_PRLI_ACC 0x02100014 | ||
172 | #define LS_PLOGI 0x03000000 | ||
173 | #define LS_FLOGI 0x04000000 | ||
174 | #define LS_LOGO 0x05000000 | ||
175 | #define LS_ABTX 0x06000000 | ||
176 | #define LS_RCS 0x07000000 | ||
177 | #define LS_RES 0x08000000 | ||
178 | #define LS_RSS 0x09000000 | ||
179 | #define LS_RSI 0x0a000000 | ||
180 | #define LS_ESTS 0x0b000000 | ||
181 | #define LS_ESTC 0x0c000000 | ||
182 | #define LS_ADVC 0x0d000000 | ||
183 | #define LS_RTV 0x0e000000 | ||
184 | #define LS_RLS 0x0f000000 | ||
185 | #define LS_ECHO 0x10000000 | ||
186 | #define LS_TEST 0x11000000 | ||
187 | #define LS_RRQ 0x12000000 | ||
188 | #define LS_IDENT 0x20000000 | ||
189 | #define LS_PRLI 0x20100014 | ||
190 | #define LS_DISPLAY 0x21000000 | ||
191 | #define LS_PRLO 0x21100014 | ||
192 | #define LS_PDISC 0x50000000 | ||
193 | #define LS_ADISC 0x52000000 | ||
194 | |||
195 | typedef struct { | ||
196 | u8 fcph_hi, fcph_lo; | ||
197 | u16 buf2buf_credit; | ||
198 | u8 common_features; | ||
199 | u8 xxx1; | ||
200 | u16 buf2buf_size; | ||
201 | u8 xxx2; | ||
202 | u8 total_concurrent; | ||
203 | u16 off_by_info; | ||
204 | u32 e_d_tov; | ||
205 | } common_svc_parm; | ||
206 | |||
207 | typedef struct { | ||
208 | u16 serv_opts; | ||
209 | u16 initiator_ctl; | ||
210 | u16 rcpt_ctl; | ||
211 | u16 recv_size; | ||
212 | u8 xxx1; | ||
213 | u8 concurrent_seqs; | ||
214 | u16 end2end_credit; | ||
215 | u16 open_seqs_per_xchg; | ||
216 | u16 xxx2; | ||
217 | } svc_parm; | ||
218 | |||
219 | /* Login */ | ||
220 | typedef struct { | ||
221 | u32 code; | ||
222 | common_svc_parm common; | ||
223 | fc_wwn nport_wwn; | ||
224 | fc_wwn node_wwn; | ||
225 | svc_parm class1; | ||
226 | svc_parm class2; | ||
227 | svc_parm class3; | ||
228 | } logi; | ||
229 | |||
230 | #endif /* !(__FC_H) */ | ||
diff --git a/drivers/fc4/fc_syms.c b/drivers/fc4/fc_syms.c deleted file mode 100644 index bd3918ddf7ac..000000000000 --- a/drivers/fc4/fc_syms.c +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | /* | ||
2 | * We should not even be trying to compile this if we are not doing | ||
3 | * a module. | ||
4 | */ | ||
5 | #include <linux/module.h> | ||
6 | |||
7 | #ifdef CONFIG_MODULES | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/kernel.h> | ||
12 | |||
13 | #include "fcp_impl.h" | ||
14 | |||
15 | EXPORT_SYMBOL(fcp_init); | ||
16 | EXPORT_SYMBOL(fcp_release); | ||
17 | EXPORT_SYMBOL(fcp_queue_empty); | ||
18 | EXPORT_SYMBOL(fcp_receive_solicited); | ||
19 | EXPORT_SYMBOL(fc_channels); | ||
20 | EXPORT_SYMBOL(fcp_state_change); | ||
21 | EXPORT_SYMBOL(fc_do_plogi); | ||
22 | EXPORT_SYMBOL(fc_do_prli); | ||
23 | |||
24 | /* SCSI stuff */ | ||
25 | EXPORT_SYMBOL(fcp_scsi_queuecommand); | ||
26 | EXPORT_SYMBOL(fcp_scsi_abort); | ||
27 | EXPORT_SYMBOL(fcp_scsi_dev_reset); | ||
28 | EXPORT_SYMBOL(fcp_scsi_host_reset); | ||
29 | |||
30 | #endif /* CONFIG_MODULES */ | ||
diff --git a/drivers/fc4/fcp.h b/drivers/fc4/fcp.h deleted file mode 100644 index 6aa34a7a4c11..000000000000 --- a/drivers/fc4/fcp.h +++ /dev/null | |||
@@ -1,94 +0,0 @@ | |||
1 | /* fcp.h: Definitions for Fibre Channel Protocol. | ||
2 | * | ||
3 | * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
4 | * | ||
5 | */ | ||
6 | |||
7 | #ifndef __FCP_H | ||
8 | #define __FCP_H | ||
9 | |||
10 | /* FCP addressing is hierarchical with up to 4 layers, MS first. | ||
11 | Exact meaning of the addresses is up to the vendor */ | ||
12 | |||
13 | /* fcp_cntl field */ | ||
14 | #define FCP_CNTL_WRITE 0x00000001 /* Initiator write */ | ||
15 | #define FCP_CNTL_READ 0x00000002 /* Initiator read */ | ||
16 | #define FCP_CNTL_ABORT_TSK 0x00000200 /* Abort task set */ | ||
17 | #define FCP_CNTL_CLR_TASK 0x00000400 /* Clear task set */ | ||
18 | #define FCP_CNTL_RESET 0x00002000 /* Reset */ | ||
19 | #define FCP_CNTL_CLR_ACA 0x00004000 /* Clear ACA */ | ||
20 | #define FCP_CNTL_KILL_TASK 0x00008000 /* Terminate task */ | ||
21 | #define FCP_CNTL_QTYPE_MASK 0x00070000 /* Tagged queueing type */ | ||
22 | #define FCP_CNTL_QTYPE_SIMPLE 0x00000000 | ||
23 | #define FCP_CNTL_QTYPE_HEAD_OF_Q 0x00010000 | ||
24 | #define FCP_CNTL_QTYPE_ORDERED 0x00020000 | ||
25 | #define FCP_CNTL_QTYPE_ACA_Q_TAG 0x00040000 | ||
26 | #define FCP_CNTL_QTYPE_UNTAGGED 0x00050000 | ||
27 | |||
28 | typedef struct { | ||
29 | u16 fcp_addr[4]; | ||
30 | u32 fcp_cntl; | ||
31 | u8 fcp_cdb[16]; | ||
32 | u32 fcp_data_len; | ||
33 | } fcp_cmd; | ||
34 | |||
35 | /* fcp_status field */ | ||
36 | #define FCP_STATUS_MASK 0x000000ff /* scsi status of command */ | ||
37 | #define FCP_STATUS_RSP_LEN 0x00000100 /* response_len != 0 */ | ||
38 | #define FCP_STATUS_SENSE_LEN 0x00000200 /* sense_len != 0 */ | ||
39 | #define FCP_STATUS_RESID 0x00000400 /* resid != 0 */ | ||
40 | |||
41 | typedef struct { | ||
42 | u32 xxx[2]; | ||
43 | u32 fcp_status; | ||
44 | u32 fcp_resid; | ||
45 | u32 fcp_sense_len; | ||
46 | u32 fcp_response_len; | ||
47 | /* u8 fcp_sense[fcp_sense_len]; */ | ||
48 | /* u8 fcp_response[fcp_response_len]; */ | ||
49 | } fcp_rsp; | ||
50 | |||
51 | /* fcp errors */ | ||
52 | |||
53 | /* rsp_info_type field */ | ||
54 | #define FCP_RSP_SCSI_BUS_ERR 0x01 | ||
55 | #define FCP_RSP_SCSI_PORT_ERR 0x02 | ||
56 | #define FCP_RSP_CARD_ERR 0x03 | ||
57 | |||
58 | /* isp_status field */ | ||
59 | #define FCP_RSP_CMD_COMPLETE 0x0000 | ||
60 | #define FCP_RSP_CMD_INCOMPLETE 0x0001 | ||
61 | #define FCP_RSP_CMD_DMA_ERR 0x0002 | ||
62 | #define FCP_RSP_CMD_TRAN_ERR 0x0003 | ||
63 | #define FCP_RSP_CMD_RESET 0x0004 | ||
64 | #define FCP_RSP_CMD_ABORTED 0x0005 | ||
65 | #define FCP_RSP_CMD_TIMEOUT 0x0006 | ||
66 | #define FCP_RSP_CMD_OVERRUN 0x0007 | ||
67 | |||
68 | /* isp_state_flags field */ | ||
69 | #define FCP_RSP_ST_GOT_BUS 0x0100 | ||
70 | #define FCP_RSP_ST_GOT_TARGET 0x0200 | ||
71 | #define FCP_RSP_ST_SENT_CMD 0x0400 | ||
72 | #define FCP_RSP_ST_XFRD_DATA 0x0800 | ||
73 | #define FCP_RSP_ST_GOT_STATUS 0x1000 | ||
74 | #define FCP_RSP_ST_GOT_SENSE 0x2000 | ||
75 | |||
76 | /* isp_stat_flags field */ | ||
77 | #define FCP_RSP_STAT_DISC 0x0001 | ||
78 | #define FCP_RSP_STAT_SYNC 0x0002 | ||
79 | #define FCP_RSP_STAT_PERR 0x0004 | ||
80 | #define FCP_RSP_STAT_BUS_RESET 0x0008 | ||
81 | #define FCP_RSP_STAT_DEV_RESET 0x0010 | ||
82 | #define FCP_RSP_STAT_ABORTED 0x0020 | ||
83 | #define FCP_RSP_STAT_TIMEOUT 0x0040 | ||
84 | #define FCP_RSP_STAT_NEGOTIATE 0x0080 | ||
85 | |||
86 | typedef struct { | ||
87 | u8 rsp_info_type; | ||
88 | u8 xxx; | ||
89 | u16 isp_status; | ||
90 | u16 isp_state_flags; | ||
91 | u16 isp_stat_flags; | ||
92 | } fcp_scsi_err; | ||
93 | |||
94 | #endif /* !(__FCP_H) */ | ||
diff --git a/drivers/fc4/fcp_impl.h b/drivers/fc4/fcp_impl.h deleted file mode 100644 index 506338a461ba..000000000000 --- a/drivers/fc4/fcp_impl.h +++ /dev/null | |||
@@ -1,164 +0,0 @@ | |||
1 | /* fcp_impl.h: Generic SCSI on top of FC4 - our interface defines. | ||
2 | * | ||
3 | * Copyright (C) 1997-1999 Jakub Jelinek (jj@ultra.linux.cz) | ||
4 | * Copyright (C) 1998 Jirka Hanika (geo@ff.cuni.cz) | ||
5 | */ | ||
6 | |||
7 | #ifndef _FCP_SCSI_H | ||
8 | #define _FCP_SCSI_H | ||
9 | |||
10 | #include <linux/types.h> | ||
11 | #include "../scsi/scsi.h" | ||
12 | |||
13 | #include "fc.h" | ||
14 | #include "fcp.h" | ||
15 | #include "fc-al.h" | ||
16 | |||
17 | #include <asm/io.h> | ||
18 | #ifdef __sparc__ | ||
19 | #include <asm/sbus.h> | ||
20 | #endif | ||
21 | |||
22 | /* 0 or 1 */ | ||
23 | #define FCP_SCSI_USE_NEW_EH_CODE 0 | ||
24 | |||
25 | #define FC_CLASS_OUTBOUND 0x01 | ||
26 | #define FC_CLASS_INBOUND 0x02 | ||
27 | #define FC_CLASS_SIMPLE 0x03 | ||
28 | #define FC_CLASS_IO_WRITE 0x04 | ||
29 | #define FC_CLASS_IO_READ 0x05 | ||
30 | #define FC_CLASS_UNSOLICITED 0x06 | ||
31 | #define FC_CLASS_OFFLINE 0x08 | ||
32 | |||
33 | #define PROTO_OFFLINE 0x02 | ||
34 | #define PROTO_REPORT_AL_MAP 0x03 | ||
35 | #define PROTO_FORCE_LIP 0x06 | ||
36 | |||
37 | struct _fc_channel; | ||
38 | |||
39 | typedef struct fcp_cmnd { | ||
40 | struct fcp_cmnd *next; | ||
41 | struct fcp_cmnd *prev; | ||
42 | void (*done)(struct scsi_cmnd *); | ||
43 | unsigned short proto; | ||
44 | unsigned short token; | ||
45 | unsigned int did; | ||
46 | /* FCP SCSI stuff */ | ||
47 | dma_addr_t data; | ||
48 | /* From now on this cannot be touched for proto == TYPE_SCSI_FCP */ | ||
49 | fc_hdr fch; | ||
50 | dma_addr_t cmd; | ||
51 | dma_addr_t rsp; | ||
52 | int cmdlen; | ||
53 | int rsplen; | ||
54 | int class; | ||
55 | int datalen; | ||
56 | /* This is just used as a verification during login */ | ||
57 | struct _fc_channel *fc; | ||
58 | void *ls; | ||
59 | } fcp_cmnd; | ||
60 | |||
61 | typedef struct { | ||
62 | unsigned int len; | ||
63 | unsigned char list[0]; | ||
64 | } fcp_posmap; | ||
65 | |||
66 | typedef struct _fc_channel { | ||
67 | struct _fc_channel *next; | ||
68 | int irq; | ||
69 | int state; | ||
70 | int sid; | ||
71 | int did; | ||
72 | char name[16]; | ||
73 | void (*fcp_register)(struct _fc_channel *, u8, int); | ||
74 | void (*reset)(struct _fc_channel *); | ||
75 | int (*hw_enque)(struct _fc_channel *, fcp_cmnd *); | ||
76 | fc_wwn wwn_node; | ||
77 | fc_wwn wwn_nport; | ||
78 | fc_wwn wwn_dest; | ||
79 | common_svc_parm *common_svc; | ||
80 | svc_parm *class_svcs; | ||
81 | #ifdef __sparc__ | ||
82 | struct sbus_dev *dev; | ||
83 | #else | ||
84 | struct pci_dev *dev; | ||
85 | #endif | ||
86 | struct module *module; | ||
87 | /* FCP SCSI stuff */ | ||
88 | short can_queue; | ||
89 | short abort_count; | ||
90 | int rsp_size; | ||
91 | fcp_cmd *scsi_cmd_pool; | ||
92 | char *scsi_rsp_pool; | ||
93 | dma_addr_t dma_scsi_cmd, dma_scsi_rsp; | ||
94 | unsigned long *scsi_bitmap; | ||
95 | long scsi_bitmap_end; | ||
96 | int scsi_free; | ||
97 | int (*encode_addr)(struct scsi_cmnd *, u16 *, struct _fc_channel *, fcp_cmnd *); | ||
98 | fcp_cmnd *scsi_que; | ||
99 | char scsi_name[4]; | ||
100 | fcp_cmnd **cmd_slots; | ||
101 | int channels; | ||
102 | int targets; | ||
103 | long *ages; | ||
104 | struct scsi_cmnd *rst_pkt; | ||
105 | fcp_posmap *posmap; | ||
106 | /* LOGIN stuff */ | ||
107 | fcp_cmnd *login; | ||
108 | void *ls; | ||
109 | } fc_channel; | ||
110 | |||
111 | extern fc_channel *fc_channels; | ||
112 | |||
113 | #define FC_STATE_UNINITED 0 | ||
114 | #define FC_STATE_ONLINE 1 | ||
115 | #define FC_STATE_OFFLINE 2 | ||
116 | #define FC_STATE_RESETING 3 | ||
117 | #define FC_STATE_FPORT_OK 4 | ||
118 | #define FC_STATE_MAYBEOFFLINE 5 | ||
119 | |||
120 | #define FC_STATUS_OK 0 | ||
121 | #define FC_STATUS_P_RJT 2 | ||
122 | #define FC_STATUS_F_RJT 3 | ||
123 | #define FC_STATUS_P_BSY 4 | ||
124 | #define FC_STATUS_F_BSY 5 | ||
125 | #define FC_STATUS_ERR_OFFLINE 0x11 | ||
126 | #define FC_STATUS_TIMEOUT 0x12 | ||
127 | #define FC_STATUS_ERR_OVERRUN 0x13 | ||
128 | #define FC_STATUS_POINTTOPOINT 0x15 | ||
129 | #define FC_STATUS_AL 0x16 | ||
130 | #define FC_STATUS_UNKNOWN_CQ_TYPE 0x20 | ||
131 | #define FC_STATUS_BAD_SEG_CNT 0x21 | ||
132 | #define FC_STATUS_MAX_XCHG_EXCEEDED 0x22 | ||
133 | #define FC_STATUS_BAD_XID 0x23 | ||
134 | #define FC_STATUS_XCHG_BUSY 0x24 | ||
135 | #define FC_STATUS_BAD_POOL_ID 0x25 | ||
136 | #define FC_STATUS_INSUFFICIENT_CQES 0x26 | ||
137 | #define FC_STATUS_ALLOC_FAIL 0x27 | ||
138 | #define FC_STATUS_BAD_SID 0x28 | ||
139 | #define FC_STATUS_NO_SEQ_INIT 0x29 | ||
140 | #define FC_STATUS_TIMED_OUT -1 | ||
141 | #define FC_STATUS_BAD_RSP -2 | ||
142 | |||
143 | void fcp_queue_empty(fc_channel *); | ||
144 | int fcp_init(fc_channel *); | ||
145 | void fcp_release(fc_channel *fc_chain, int count); | ||
146 | void fcp_receive_solicited(fc_channel *, int, int, int, fc_hdr *); | ||
147 | void fcp_state_change(fc_channel *, int); | ||
148 | int fc_do_plogi(fc_channel *, unsigned char, fc_wwn *, fc_wwn *); | ||
149 | int fc_do_prli(fc_channel *, unsigned char); | ||
150 | |||
151 | #define for_each_fc_channel(fc) \ | ||
152 | for (fc = fc_channels; fc; fc = fc->next) | ||
153 | |||
154 | #define for_each_online_fc_channel(fc) \ | ||
155 | for_each_fc_channel(fc) \ | ||
156 | if (fc->state == FC_STATE_ONLINE) | ||
157 | |||
158 | int fcp_scsi_queuecommand(struct scsi_cmnd *, | ||
159 | void (* done) (struct scsi_cmnd *)); | ||
160 | int fcp_scsi_abort(struct scsi_cmnd *); | ||
161 | int fcp_scsi_dev_reset(struct scsi_cmnd *); | ||
162 | int fcp_scsi_host_reset(struct scsi_cmnd *); | ||
163 | |||
164 | #endif /* !(_FCP_SCSI_H) */ | ||
diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c deleted file mode 100644 index d517734462e6..000000000000 --- a/drivers/fc4/soc.c +++ /dev/null | |||
@@ -1,764 +0,0 @@ | |||
1 | /* soc.c: Sparc SUNW,soc (Serial Optical Channel) Fibre Channel Sbus adapter support. | ||
2 | * | ||
3 | * Copyright (C) 1996,1997,1999 Jakub Jelinek (jj@ultra.linux.cz) | ||
4 | * Copyright (C) 1997,1998 Jirka Hanika (geo@ff.cuni.cz) | ||
5 | * | ||
6 | * Sources: | ||
7 | * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994 | ||
8 | * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995 | ||
9 | * | ||
10 | * Supported hardware: | ||
11 | * Tested on SOC sbus card bought with SS1000 in Linux running on SS5 and Ultra1. | ||
12 | * For SOC sbus cards, you have to make sure your FCode is 1.52 or later. | ||
13 | * If you have older FCode, you should try to upgrade or get SOC microcode from Sun | ||
14 | * (the microcode is present in Solaris soc driver as well). In that case you need | ||
15 | * to #define HAVE_SOC_UCODE and format the microcode into soc_asm.c. For the exact | ||
16 | * format mail me and I will tell you. I cannot offer you the actual microcode though, | ||
17 | * unless Sun confirms they don't mind. | ||
18 | */ | ||
19 | |||
20 | static char *version = | ||
21 | "soc.c:v1.3 9/Feb/99 Jakub Jelinek (jj@ultra.linux.cz), Jirka Hanika (geo@ff.cuni.cz)\n"; | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/fcntl.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/ptrace.h> | ||
29 | #include <linux/ioport.h> | ||
30 | #include <linux/in.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/string.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/bitops.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/dma.h> | ||
37 | #include <linux/errno.h> | ||
38 | #include <asm/byteorder.h> | ||
39 | |||
40 | #include <asm/openprom.h> | ||
41 | #include <asm/oplib.h> | ||
42 | #include <asm/pgtable.h> | ||
43 | #include <asm/irq.h> | ||
44 | |||
45 | /* #define SOCDEBUG */ | ||
46 | /* #define HAVE_SOC_UCODE */ | ||
47 | |||
48 | #include "fcp_impl.h" | ||
49 | #include "soc.h" | ||
50 | #ifdef HAVE_SOC_UCODE | ||
51 | #include "soc_asm.h" | ||
52 | #endif | ||
53 | |||
54 | #define soc_printk printk ("soc%d: ", s->soc_no); printk | ||
55 | |||
56 | #ifdef SOCDEBUG | ||
57 | #define SOD(x) soc_printk x; | ||
58 | #else | ||
59 | #define SOD(x) | ||
60 | #endif | ||
61 | |||
62 | #define for_each_soc(s) for (s = socs; s; s = s->next) | ||
63 | struct soc *socs = NULL; | ||
64 | |||
65 | static inline void soc_disable(struct soc *s) | ||
66 | { | ||
67 | sbus_writel(0, s->regs + IMASK); | ||
68 | sbus_writel(SOC_CMD_SOFT_RESET, s->regs + CMD); | ||
69 | } | ||
70 | |||
71 | static inline void soc_enable(struct soc *s) | ||
72 | { | ||
73 | SOD(("enable %08x\n", s->cfg)) | ||
74 | sbus_writel(0, s->regs + SAE); | ||
75 | sbus_writel(s->cfg, s->regs + CFG); | ||
76 | sbus_writel(SOC_CMD_RSP_QALL, s->regs + CMD); | ||
77 | SOC_SETIMASK(s, SOC_IMASK_RSP_QALL | SOC_IMASK_SAE); | ||
78 | SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMAK))); | ||
79 | } | ||
80 | |||
81 | static void soc_reset(fc_channel *fc) | ||
82 | { | ||
83 | soc_port *port = (soc_port *)fc; | ||
84 | struct soc *s = port->s; | ||
85 | |||
86 | /* FIXME */ | ||
87 | soc_disable(s); | ||
88 | s->req[0].seqno = 1; | ||
89 | s->req[1].seqno = 1; | ||
90 | s->rsp[0].seqno = 1; | ||
91 | s->rsp[1].seqno = 1; | ||
92 | s->req[0].in = 0; | ||
93 | s->req[1].in = 0; | ||
94 | s->rsp[0].in = 0; | ||
95 | s->rsp[1].in = 0; | ||
96 | s->req[0].out = 0; | ||
97 | s->req[1].out = 0; | ||
98 | s->rsp[0].out = 0; | ||
99 | s->rsp[1].out = 0; | ||
100 | |||
101 | /* FIXME */ | ||
102 | soc_enable(s); | ||
103 | } | ||
104 | |||
105 | static inline void soc_solicited (struct soc *s) | ||
106 | { | ||
107 | fc_hdr fchdr; | ||
108 | soc_rsp __iomem *hwrsp; | ||
109 | soc_cq_rsp *sw_cq; | ||
110 | int token; | ||
111 | int status; | ||
112 | fc_channel *fc; | ||
113 | |||
114 | sw_cq = &s->rsp[SOC_SOLICITED_RSP_Q]; | ||
115 | |||
116 | if (sw_cq->pool == NULL) | ||
117 | sw_cq->pool = (soc_req __iomem *) | ||
118 | (s->xram + xram_get_32low ((xram_p)&sw_cq->hw_cq->address)); | ||
119 | sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); | ||
120 | SOD (("soc_solicited, %d pkts arrived\n", (sw_cq->in-sw_cq->out) & sw_cq->last)) | ||
121 | for (;;) { | ||
122 | hwrsp = (soc_rsp __iomem *)sw_cq->pool + sw_cq->out; | ||
123 | token = xram_get_32low ((xram_p)&hwrsp->shdr.token); | ||
124 | status = xram_get_32low ((xram_p)&hwrsp->status); | ||
125 | fc = (fc_channel *)(&s->port[(token >> 11) & 1]); | ||
126 | |||
127 | if (status == SOC_OK) { | ||
128 | fcp_receive_solicited(fc, token >> 12, | ||
129 | token & ((1 << 11) - 1), | ||
130 | FC_STATUS_OK, NULL); | ||
131 | } else { | ||
132 | xram_copy_from(&fchdr, (xram_p)&hwrsp->fchdr, sizeof(fchdr)); | ||
133 | /* We have intentionally defined FC_STATUS_* constants | ||
134 | * to match SOC_* constants, otherwise we'd have to | ||
135 | * translate status. | ||
136 | */ | ||
137 | fcp_receive_solicited(fc, token >> 12, | ||
138 | token & ((1 << 11) - 1), | ||
139 | status, &fchdr); | ||
140 | } | ||
141 | |||
142 | if (++sw_cq->out > sw_cq->last) { | ||
143 | sw_cq->seqno++; | ||
144 | sw_cq->out = 0; | ||
145 | } | ||
146 | |||
147 | if (sw_cq->out == sw_cq->in) { | ||
148 | sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); | ||
149 | if (sw_cq->out == sw_cq->in) { | ||
150 | /* Tell the hardware about it */ | ||
151 | sbus_writel((sw_cq->out << 24) | | ||
152 | (SOC_CMD_RSP_QALL & | ||
153 | ~(SOC_CMD_RSP_Q0 << SOC_SOLICITED_RSP_Q)), | ||
154 | s->regs + CMD); | ||
155 | |||
156 | /* Read it, so that we're sure it has been updated */ | ||
157 | sbus_readl(s->regs + CMD); | ||
158 | sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); | ||
159 | if (sw_cq->out == sw_cq->in) | ||
160 | break; | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
166 | static inline void soc_request (struct soc *s, u32 cmd) | ||
167 | { | ||
168 | SOC_SETIMASK(s, s->imask & ~(cmd & SOC_CMD_REQ_QALL)); | ||
169 | SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMASK))); | ||
170 | |||
171 | SOD(("Queues available %08x OUT %X %X\n", cmd, | ||
172 | xram_get_8((xram_p)&s->req[0].hw_cq->out), | ||
173 | xram_get_8((xram_p)&s->req[0].hw_cq->out))) | ||
174 | if (s->port[s->curr_port].fc.state != FC_STATE_OFFLINE) { | ||
175 | fcp_queue_empty ((fc_channel *)&(s->port[s->curr_port])); | ||
176 | if (((s->req[1].in + 1) & s->req[1].last) != (s->req[1].out)) | ||
177 | fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); | ||
178 | } else { | ||
179 | fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); | ||
180 | } | ||
181 | if (s->port[1 - s->curr_port].fc.state != FC_STATE_OFFLINE) | ||
182 | s->curr_port ^= 1; | ||
183 | } | ||
184 | |||
185 | static inline void soc_unsolicited (struct soc *s) | ||
186 | { | ||
187 | soc_rsp __iomem *hwrsp, *hwrspc; | ||
188 | soc_cq_rsp *sw_cq; | ||
189 | int count; | ||
190 | int status; | ||
191 | int flags; | ||
192 | fc_channel *fc; | ||
193 | |||
194 | sw_cq = &s->rsp[SOC_UNSOLICITED_RSP_Q]; | ||
195 | if (sw_cq->pool == NULL) | ||
196 | sw_cq->pool = (soc_req __iomem *) | ||
197 | (s->xram + (xram_get_32low ((xram_p)&sw_cq->hw_cq->address))); | ||
198 | |||
199 | sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); | ||
200 | SOD (("soc_unsolicited, %d packets arrived\n", (sw_cq->in - sw_cq->out) & sw_cq->last)) | ||
201 | while (sw_cq->in != sw_cq->out) { | ||
202 | /* ...real work per entry here... */ | ||
203 | hwrsp = (soc_rsp __iomem *)sw_cq->pool + sw_cq->out; | ||
204 | |||
205 | hwrspc = NULL; | ||
206 | flags = xram_get_16 ((xram_p)&hwrsp->shdr.flags); | ||
207 | count = xram_get_8 ((xram_p)&hwrsp->count); | ||
208 | fc = (fc_channel *)&s->port[flags & SOC_PORT_B]; | ||
209 | SOD(("FC %08lx fcp_state_change %08lx\n", | ||
210 | (long)fc, (long)fc->fcp_state_change)) | ||
211 | |||
212 | if (count != 1) { | ||
213 | /* Ugh, continuation entries */ | ||
214 | u8 in; | ||
215 | |||
216 | if (count != 2) { | ||
217 | printk("%s: Too many continuations entries %d\n", | ||
218 | fc->name, count); | ||
219 | goto update_out; | ||
220 | } | ||
221 | |||
222 | in = sw_cq->in; | ||
223 | if (in < sw_cq->out) in += sw_cq->last + 1; | ||
224 | if (in < sw_cq->out + 2) { | ||
225 | /* Ask the hardware if they haven't arrived yet. */ | ||
226 | sbus_writel((sw_cq->out << 24) | | ||
227 | (SOC_CMD_RSP_QALL & | ||
228 | ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)), | ||
229 | s->regs + CMD); | ||
230 | |||
231 | /* Read it, so that we're sure it has been updated */ | ||
232 | sbus_readl(s->regs + CMD); | ||
233 | sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); | ||
234 | in = sw_cq->in; | ||
235 | if (in < sw_cq->out) | ||
236 | in += sw_cq->last + 1; | ||
237 | if (in < sw_cq->out + 2) /* Nothing came, let us wait */ | ||
238 | return; | ||
239 | } | ||
240 | if (sw_cq->out == sw_cq->last) | ||
241 | hwrspc = (soc_rsp __iomem *)sw_cq->pool; | ||
242 | else | ||
243 | hwrspc = hwrsp + 1; | ||
244 | } | ||
245 | |||
246 | switch (flags & ~SOC_PORT_B) { | ||
247 | case SOC_STATUS: | ||
248 | status = xram_get_32low ((xram_p)&hwrsp->status); | ||
249 | switch (status) { | ||
250 | case SOC_ONLINE: | ||
251 | SOD(("State change to ONLINE\n")); | ||
252 | fcp_state_change(fc, FC_STATE_ONLINE); | ||
253 | break; | ||
254 | case SOC_OFFLINE: | ||
255 | SOD(("State change to OFFLINE\n")); | ||
256 | fcp_state_change(fc, FC_STATE_OFFLINE); | ||
257 | break; | ||
258 | default: | ||
259 | printk ("%s: Unknown STATUS no %d\n", | ||
260 | fc->name, status); | ||
261 | break; | ||
262 | } | ||
263 | break; | ||
264 | case (SOC_UNSOLICITED|SOC_FC_HDR): | ||
265 | { | ||
266 | int r_ctl = xram_get_8 ((xram_p)&hwrsp->fchdr); | ||
267 | unsigned len; | ||
268 | char buf[64]; | ||
269 | |||
270 | if ((r_ctl & 0xf0) == R_CTL_EXTENDED_SVC) { | ||
271 | len = xram_get_32 ((xram_p)&hwrsp->shdr.bytecnt); | ||
272 | if (len < 4 || !hwrspc) { | ||
273 | printk ("%s: Invalid R_CTL %02x " | ||
274 | "continuation entries\n", | ||
275 | fc->name, r_ctl); | ||
276 | } else { | ||
277 | if (len > 60) | ||
278 | len = 60; | ||
279 | xram_copy_from (buf, (xram_p)hwrspc, | ||
280 | (len + 3) & ~3); | ||
281 | if (*(u32 *)buf == LS_DISPLAY) { | ||
282 | int i; | ||
283 | |||
284 | for (i = 4; i < len; i++) | ||
285 | if (buf[i] == '\n') | ||
286 | buf[i] = ' '; | ||
287 | buf[len] = 0; | ||
288 | printk ("%s message: %s\n", | ||
289 | fc->name, buf + 4); | ||
290 | } else { | ||
291 | printk ("%s: Unknown LS_CMD " | ||
292 | "%02x\n", fc->name, | ||
293 | buf[0]); | ||
294 | } | ||
295 | } | ||
296 | } else { | ||
297 | printk ("%s: Unsolicited R_CTL %02x " | ||
298 | "not handled\n", fc->name, r_ctl); | ||
299 | } | ||
300 | } | ||
301 | break; | ||
302 | default: | ||
303 | printk ("%s: Unexpected flags %08x\n", fc->name, flags); | ||
304 | break; | ||
305 | }; | ||
306 | update_out: | ||
307 | if (++sw_cq->out > sw_cq->last) { | ||
308 | sw_cq->seqno++; | ||
309 | sw_cq->out = 0; | ||
310 | } | ||
311 | |||
312 | if (hwrspc) { | ||
313 | if (++sw_cq->out > sw_cq->last) { | ||
314 | sw_cq->seqno++; | ||
315 | sw_cq->out = 0; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | if (sw_cq->out == sw_cq->in) { | ||
320 | sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); | ||
321 | if (sw_cq->out == sw_cq->in) { | ||
322 | /* Tell the hardware about it */ | ||
323 | sbus_writel((sw_cq->out << 24) | | ||
324 | (SOC_CMD_RSP_QALL & | ||
325 | ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)), | ||
326 | s->regs + CMD); | ||
327 | |||
328 | /* Read it, so that we're sure it has been updated */ | ||
329 | sbus_readl(s->regs + CMD); | ||
330 | sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | } | ||
335 | |||
336 | static irqreturn_t soc_intr(int irq, void *dev_id) | ||
337 | { | ||
338 | u32 cmd; | ||
339 | unsigned long flags; | ||
340 | register struct soc *s = (struct soc *)dev_id; | ||
341 | |||
342 | spin_lock_irqsave(&s->lock, flags); | ||
343 | cmd = sbus_readl(s->regs + CMD); | ||
344 | for (; (cmd = SOC_INTR (s, cmd)); cmd = sbus_readl(s->regs + CMD)) { | ||
345 | if (cmd & SOC_CMD_RSP_Q1) soc_unsolicited (s); | ||
346 | if (cmd & SOC_CMD_RSP_Q0) soc_solicited (s); | ||
347 | if (cmd & SOC_CMD_REQ_QALL) soc_request (s, cmd); | ||
348 | } | ||
349 | spin_unlock_irqrestore(&s->lock, flags); | ||
350 | |||
351 | return IRQ_HANDLED; | ||
352 | } | ||
353 | |||
354 | #define TOKEN(proto, port, token) (((proto)<<12)|(token)|(port)) | ||
355 | |||
356 | static int soc_hw_enque (fc_channel *fc, fcp_cmnd *fcmd) | ||
357 | { | ||
358 | soc_port *port = (soc_port *)fc; | ||
359 | struct soc *s = port->s; | ||
360 | int qno; | ||
361 | soc_cq_req *sw_cq; | ||
362 | int cq_next_in; | ||
363 | soc_req *request; | ||
364 | fc_hdr *fch; | ||
365 | int i; | ||
366 | |||
367 | if (fcmd->proto == TYPE_SCSI_FCP) | ||
368 | qno = 1; | ||
369 | else | ||
370 | qno = 0; | ||
371 | SOD(("Putting a FCP packet type %d into hw queue %d\n", fcmd->proto, qno)) | ||
372 | if (s->imask & (SOC_IMASK_REQ_Q0 << qno)) { | ||
373 | SOD(("EIO %08x\n", s->imask)) | ||
374 | return -EIO; | ||
375 | } | ||
376 | sw_cq = s->req + qno; | ||
377 | cq_next_in = (sw_cq->in + 1) & sw_cq->last; | ||
378 | |||
379 | if (cq_next_in == sw_cq->out && | ||
380 | cq_next_in == (sw_cq->out = xram_get_8((xram_p)&sw_cq->hw_cq->out))) { | ||
381 | SOD(("%d IN %d OUT %d LAST %d\n", qno, sw_cq->in, sw_cq->out, sw_cq->last)) | ||
382 | SOC_SETIMASK(s, s->imask | (SOC_IMASK_REQ_Q0 << qno)); | ||
383 | SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMASK))); | ||
384 | /* If queue is full, just say NO */ | ||
385 | return -EBUSY; | ||
386 | } | ||
387 | |||
388 | request = sw_cq->pool + sw_cq->in; | ||
389 | fch = &request->fchdr; | ||
390 | |||
391 | switch (fcmd->proto) { | ||
392 | case TYPE_SCSI_FCP: | ||
393 | request->shdr.token = TOKEN(TYPE_SCSI_FCP, port->mask, fcmd->token); | ||
394 | request->data[0].base = fc->dma_scsi_cmd + fcmd->token * sizeof(fcp_cmd); | ||
395 | request->data[0].count = sizeof(fcp_cmd); | ||
396 | request->data[1].base = fc->dma_scsi_rsp + fcmd->token * fc->rsp_size; | ||
397 | request->data[1].count = fc->rsp_size; | ||
398 | if (fcmd->data) { | ||
399 | request->shdr.segcnt = 3; | ||
400 | i = fc->scsi_cmd_pool[fcmd->token].fcp_data_len; | ||
401 | request->shdr.bytecnt = i; | ||
402 | request->data[2].base = fcmd->data; | ||
403 | request->data[2].count = i; | ||
404 | request->type = | ||
405 | (fc->scsi_cmd_pool[fcmd->token].fcp_cntl & FCP_CNTL_WRITE) ? | ||
406 | SOC_CQTYPE_IO_WRITE : SOC_CQTYPE_IO_READ; | ||
407 | } else { | ||
408 | request->shdr.segcnt = 2; | ||
409 | request->shdr.bytecnt = 0; | ||
410 | request->data[2].base = 0; | ||
411 | request->data[2].count = 0; | ||
412 | request->type = SOC_CQTYPE_SIMPLE; | ||
413 | } | ||
414 | FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fc->did); | ||
415 | FILL_FCHDR_SID(fch, fc->sid); | ||
416 | FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, | ||
417 | F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); | ||
418 | FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); | ||
419 | FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); | ||
420 | fch->param = 0; | ||
421 | request->shdr.flags = port->flags; | ||
422 | request->shdr.class = 2; | ||
423 | break; | ||
424 | |||
425 | case PROTO_OFFLINE: | ||
426 | memset (request, 0, sizeof(*request)); | ||
427 | request->shdr.token = TOKEN(PROTO_OFFLINE, port->mask, fcmd->token); | ||
428 | request->type = SOC_CQTYPE_OFFLINE; | ||
429 | FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fc->did); | ||
430 | FILL_FCHDR_SID(fch, fc->sid); | ||
431 | FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, | ||
432 | F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); | ||
433 | FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); | ||
434 | FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); | ||
435 | request->shdr.flags = port->flags; | ||
436 | break; | ||
437 | |||
438 | case PROTO_REPORT_AL_MAP: | ||
439 | /* SOC only supports Point-to-Point topology, no FC-AL, sorry... */ | ||
440 | return -ENOSYS; | ||
441 | |||
442 | default: | ||
443 | request->shdr.token = TOKEN(fcmd->proto, port->mask, fcmd->token); | ||
444 | request->shdr.class = 2; | ||
445 | request->shdr.flags = port->flags; | ||
446 | memcpy (fch, &fcmd->fch, sizeof(fc_hdr)); | ||
447 | request->data[0].count = fcmd->cmdlen; | ||
448 | request->data[1].count = fcmd->rsplen; | ||
449 | request->type = fcmd->class; | ||
450 | switch (fcmd->class) { | ||
451 | case FC_CLASS_OUTBOUND: | ||
452 | request->data[0].base = fcmd->cmd; | ||
453 | request->data[0].count = fcmd->cmdlen; | ||
454 | request->type = SOC_CQTYPE_OUTBOUND; | ||
455 | request->shdr.bytecnt = fcmd->cmdlen; | ||
456 | request->shdr.segcnt = 1; | ||
457 | break; | ||
458 | case FC_CLASS_INBOUND: | ||
459 | request->data[0].base = fcmd->rsp; | ||
460 | request->data[0].count = fcmd->rsplen; | ||
461 | request->type = SOC_CQTYPE_INBOUND; | ||
462 | request->shdr.bytecnt = 0; | ||
463 | request->shdr.segcnt = 1; | ||
464 | break; | ||
465 | case FC_CLASS_SIMPLE: | ||
466 | request->data[0].base = fcmd->cmd; | ||
467 | request->data[1].base = fcmd->rsp; | ||
468 | request->data[0].count = fcmd->cmdlen; | ||
469 | request->data[1].count = fcmd->rsplen; | ||
470 | request->type = SOC_CQTYPE_SIMPLE; | ||
471 | request->shdr.bytecnt = fcmd->cmdlen; | ||
472 | request->shdr.segcnt = 2; | ||
473 | break; | ||
474 | case FC_CLASS_IO_READ: | ||
475 | case FC_CLASS_IO_WRITE: | ||
476 | request->data[0].base = fcmd->cmd; | ||
477 | request->data[1].base = fcmd->rsp; | ||
478 | request->data[0].count = fcmd->cmdlen; | ||
479 | request->data[1].count = fcmd->rsplen; | ||
480 | request->type = | ||
481 | (fcmd->class == FC_CLASS_IO_READ) ? | ||
482 | SOC_CQTYPE_IO_READ : SOC_CQTYPE_IO_WRITE; | ||
483 | if (fcmd->data) { | ||
484 | request->data[2].base = fcmd->data; | ||
485 | request->data[2].count = fcmd->datalen; | ||
486 | request->shdr.bytecnt = fcmd->datalen; | ||
487 | request->shdr.segcnt = 3; | ||
488 | } else { | ||
489 | request->shdr.bytecnt = 0; | ||
490 | request->shdr.segcnt = 2; | ||
491 | } | ||
492 | break; | ||
493 | }; | ||
494 | break; | ||
495 | }; | ||
496 | |||
497 | request->count = 1; | ||
498 | request->flags = 0; | ||
499 | request->seqno = sw_cq->seqno; | ||
500 | |||
501 | /* And now tell the SOC about it */ | ||
502 | |||
503 | if (++sw_cq->in > sw_cq->last) { | ||
504 | sw_cq->in = 0; | ||
505 | sw_cq->seqno++; | ||
506 | } | ||
507 | |||
508 | SOD(("Putting %08x into cmd\n", | ||
509 | SOC_CMD_RSP_QALL | (sw_cq->in << 24) | (SOC_CMD_REQ_Q0 << qno))) | ||
510 | |||
511 | sbus_writel(SOC_CMD_RSP_QALL | (sw_cq->in << 24) | (SOC_CMD_REQ_Q0 << qno), | ||
512 | s->regs + CMD); | ||
513 | |||
514 | /* Read so that command is completed. */ | ||
515 | sbus_readl(s->regs + CMD); | ||
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static inline void soc_download_fw(struct soc *s) | ||
521 | { | ||
522 | #ifdef HAVE_SOC_UCODE | ||
523 | xram_copy_to (s->xram, soc_ucode, sizeof(soc_ucode)); | ||
524 | xram_bzero (s->xram + sizeof(soc_ucode), 32768 - sizeof(soc_ucode)); | ||
525 | #endif | ||
526 | } | ||
527 | |||
528 | /* Check for what the best SBUS burst we can use happens | ||
529 | * to be on this machine. | ||
530 | */ | ||
531 | static inline void soc_init_bursts(struct soc *s, struct sbus_dev *sdev) | ||
532 | { | ||
533 | int bsizes, bsizes_more; | ||
534 | |||
535 | bsizes = (prom_getintdefault(sdev->prom_node,"burst-sizes",0xff) & 0xff); | ||
536 | bsizes_more = (prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff) & 0xff); | ||
537 | bsizes &= bsizes_more; | ||
538 | if ((bsizes & 0x7f) == 0x7f) | ||
539 | s->cfg = SOC_CFG_BURST_64; | ||
540 | else if ((bsizes & 0x3f) == 0x3f) | ||
541 | s->cfg = SOC_CFG_BURST_32; | ||
542 | else if ((bsizes & 0x1f) == 0x1f) | ||
543 | s->cfg = SOC_CFG_BURST_16; | ||
544 | else | ||
545 | s->cfg = SOC_CFG_BURST_4; | ||
546 | } | ||
547 | |||
548 | static inline void soc_init(struct sbus_dev *sdev, int no) | ||
549 | { | ||
550 | unsigned char tmp[60]; | ||
551 | int propl; | ||
552 | struct soc *s; | ||
553 | static int version_printed = 0; | ||
554 | soc_hw_cq cq[8]; | ||
555 | int size, i; | ||
556 | int irq; | ||
557 | |||
558 | s = kzalloc (sizeof (struct soc), GFP_KERNEL); | ||
559 | if (s == NULL) | ||
560 | return; | ||
561 | spin_lock_init(&s->lock); | ||
562 | s->soc_no = no; | ||
563 | |||
564 | SOD(("socs %08lx soc_intr %08lx soc_hw_enque %08x\n", | ||
565 | (long)socs, (long)soc_intr, (long)soc_hw_enque)) | ||
566 | if (version_printed++ == 0) | ||
567 | printk (version); | ||
568 | |||
569 | s->port[0].fc.module = THIS_MODULE; | ||
570 | s->port[1].fc.module = THIS_MODULE; | ||
571 | |||
572 | s->next = socs; | ||
573 | socs = s; | ||
574 | s->port[0].fc.dev = sdev; | ||
575 | s->port[1].fc.dev = sdev; | ||
576 | s->port[0].s = s; | ||
577 | s->port[1].s = s; | ||
578 | |||
579 | s->port[0].fc.next = &s->port[1].fc; | ||
580 | |||
581 | /* World Wide Name of SOC */ | ||
582 | propl = prom_getproperty (sdev->prom_node, "soc-wwn", tmp, sizeof(tmp)); | ||
583 | if (propl != sizeof (fc_wwn)) { | ||
584 | s->wwn.naaid = NAAID_IEEE; | ||
585 | s->wwn.lo = 0x12345678; | ||
586 | } else | ||
587 | memcpy (&s->wwn, tmp, sizeof (fc_wwn)); | ||
588 | |||
589 | propl = prom_getproperty (sdev->prom_node, "port-wwns", tmp, sizeof(tmp)); | ||
590 | if (propl != 2 * sizeof (fc_wwn)) { | ||
591 | s->port[0].fc.wwn_nport.naaid = NAAID_IEEE_EXT; | ||
592 | s->port[0].fc.wwn_nport.hi = s->wwn.hi; | ||
593 | s->port[0].fc.wwn_nport.lo = s->wwn.lo; | ||
594 | s->port[1].fc.wwn_nport.naaid = NAAID_IEEE_EXT; | ||
595 | s->port[1].fc.wwn_nport.nportid = 1; | ||
596 | s->port[1].fc.wwn_nport.hi = s->wwn.hi; | ||
597 | s->port[1].fc.wwn_nport.lo = s->wwn.lo; | ||
598 | } else { | ||
599 | memcpy (&s->port[0].fc.wwn_nport, tmp, sizeof (fc_wwn)); | ||
600 | memcpy (&s->port[1].fc.wwn_nport, tmp + sizeof (fc_wwn), sizeof (fc_wwn)); | ||
601 | } | ||
602 | memcpy (&s->port[0].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); | ||
603 | memcpy (&s->port[1].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); | ||
604 | SOD(("Got wwns %08x%08x ports %08x%08x and %08x%08x\n", | ||
605 | *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, | ||
606 | *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, | ||
607 | *(u32 *)&s->port[1].fc.wwn_nport, s->port[1].fc.wwn_nport.lo)) | ||
608 | |||
609 | s->port[0].fc.sid = 1; | ||
610 | s->port[1].fc.sid = 17; | ||
611 | s->port[0].fc.did = 2; | ||
612 | s->port[1].fc.did = 18; | ||
613 | |||
614 | s->port[0].fc.reset = soc_reset; | ||
615 | s->port[1].fc.reset = soc_reset; | ||
616 | |||
617 | if (sdev->num_registers == 1) { | ||
618 | /* Probably SunFire onboard SOC */ | ||
619 | s->xram = sbus_ioremap(&sdev->resource[0], 0, | ||
620 | 0x10000UL, "soc xram"); | ||
621 | s->regs = sbus_ioremap(&sdev->resource[0], 0x10000UL, | ||
622 | 0x10UL, "soc regs"); | ||
623 | } else { | ||
624 | /* Probably SOC sbus card */ | ||
625 | s->xram = sbus_ioremap(&sdev->resource[1], 0, | ||
626 | sdev->reg_addrs[1].reg_size, "soc xram"); | ||
627 | s->regs = sbus_ioremap(&sdev->resource[2], 0, | ||
628 | sdev->reg_addrs[2].reg_size, "soc regs"); | ||
629 | } | ||
630 | |||
631 | soc_init_bursts(s, sdev); | ||
632 | |||
633 | SOD(("Disabling SOC\n")) | ||
634 | |||
635 | soc_disable (s); | ||
636 | |||
637 | irq = sdev->irqs[0]; | ||
638 | |||
639 | if (request_irq (irq, soc_intr, IRQF_SHARED, "SOC", (void *)s)) { | ||
640 | soc_printk ("Cannot order irq %d to go\n", irq); | ||
641 | socs = s->next; | ||
642 | return; | ||
643 | } | ||
644 | |||
645 | SOD(("SOC uses IRQ %d\n", irq)) | ||
646 | |||
647 | s->port[0].fc.irq = irq; | ||
648 | s->port[1].fc.irq = irq; | ||
649 | |||
650 | sprintf (s->port[0].fc.name, "soc%d port A", no); | ||
651 | sprintf (s->port[1].fc.name, "soc%d port B", no); | ||
652 | s->port[0].flags = SOC_FC_HDR | SOC_PORT_A; | ||
653 | s->port[1].flags = SOC_FC_HDR | SOC_PORT_B; | ||
654 | s->port[1].mask = (1 << 11); | ||
655 | |||
656 | s->port[0].fc.hw_enque = soc_hw_enque; | ||
657 | s->port[1].fc.hw_enque = soc_hw_enque; | ||
658 | |||
659 | soc_download_fw (s); | ||
660 | |||
661 | SOD(("Downloaded firmware\n")) | ||
662 | |||
663 | /* Now setup xram circular queues */ | ||
664 | memset (cq, 0, sizeof(cq)); | ||
665 | |||
666 | size = (SOC_CQ_REQ0_SIZE + SOC_CQ_REQ1_SIZE) * sizeof(soc_req); | ||
667 | s->req_cpu = sbus_alloc_consistent(sdev, size, &s->req_dvma); | ||
668 | s->req[0].pool = s->req_cpu; | ||
669 | cq[0].address = s->req_dvma; | ||
670 | s->req[1].pool = s->req[0].pool + SOC_CQ_REQ0_SIZE; | ||
671 | |||
672 | s->req[0].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_REQ_OFFSET); | ||
673 | s->req[1].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_REQ_OFFSET + sizeof(soc_hw_cq)); | ||
674 | s->rsp[0].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_RSP_OFFSET); | ||
675 | s->rsp[1].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_RSP_OFFSET + sizeof(soc_hw_cq)); | ||
676 | |||
677 | cq[1].address = cq[0].address + (SOC_CQ_REQ0_SIZE * sizeof(soc_req)); | ||
678 | cq[4].address = 1; | ||
679 | cq[5].address = 1; | ||
680 | cq[0].last = SOC_CQ_REQ0_SIZE - 1; | ||
681 | cq[1].last = SOC_CQ_REQ1_SIZE - 1; | ||
682 | cq[4].last = SOC_CQ_RSP0_SIZE - 1; | ||
683 | cq[5].last = SOC_CQ_RSP1_SIZE - 1; | ||
684 | for (i = 0; i < 8; i++) | ||
685 | cq[i].seqno = 1; | ||
686 | |||
687 | s->req[0].last = SOC_CQ_REQ0_SIZE - 1; | ||
688 | s->req[1].last = SOC_CQ_REQ1_SIZE - 1; | ||
689 | s->rsp[0].last = SOC_CQ_RSP0_SIZE - 1; | ||
690 | s->rsp[1].last = SOC_CQ_RSP1_SIZE - 1; | ||
691 | |||
692 | s->req[0].seqno = 1; | ||
693 | s->req[1].seqno = 1; | ||
694 | s->rsp[0].seqno = 1; | ||
695 | s->rsp[1].seqno = 1; | ||
696 | |||
697 | xram_copy_to (s->xram + SOC_CQ_REQ_OFFSET, cq, sizeof(cq)); | ||
698 | |||
699 | /* Make our sw copy of SOC service parameters */ | ||
700 | xram_copy_from (s->serv_params, s->xram + 0x140, sizeof (s->serv_params)); | ||
701 | |||
702 | s->port[0].fc.common_svc = (common_svc_parm *)s->serv_params; | ||
703 | s->port[0].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20); | ||
704 | s->port[1].fc.common_svc = (common_svc_parm *)&s->serv_params; | ||
705 | s->port[1].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20); | ||
706 | |||
707 | soc_enable (s); | ||
708 | |||
709 | SOD(("Enabled SOC\n")) | ||
710 | } | ||
711 | |||
712 | static int __init soc_probe(void) | ||
713 | { | ||
714 | struct sbus_bus *sbus; | ||
715 | struct sbus_dev *sdev = NULL; | ||
716 | struct soc *s; | ||
717 | int cards = 0; | ||
718 | |||
719 | for_each_sbus(sbus) { | ||
720 | for_each_sbusdev(sdev, sbus) { | ||
721 | if(!strcmp(sdev->prom_name, "SUNW,soc")) { | ||
722 | soc_init(sdev, cards); | ||
723 | cards++; | ||
724 | } | ||
725 | } | ||
726 | } | ||
727 | if (!cards) return -EIO; | ||
728 | |||
729 | for_each_soc(s) | ||
730 | if (s->next) | ||
731 | s->port[1].fc.next = &s->next->port[0].fc; | ||
732 | fcp_init (&socs->port[0].fc); | ||
733 | return 0; | ||
734 | } | ||
735 | |||
736 | static void __exit soc_cleanup(void) | ||
737 | { | ||
738 | struct soc *s; | ||
739 | int irq; | ||
740 | struct sbus_dev *sdev; | ||
741 | |||
742 | for_each_soc(s) { | ||
743 | irq = s->port[0].fc.irq; | ||
744 | free_irq (irq, s); | ||
745 | |||
746 | fcp_release(&(s->port[0].fc), 2); | ||
747 | |||
748 | sdev = s->port[0].fc.dev; | ||
749 | if (sdev->num_registers == 1) { | ||
750 | sbus_iounmap(s->xram, 0x10000UL); | ||
751 | sbus_iounmap(s->regs, 0x10UL); | ||
752 | } else { | ||
753 | sbus_iounmap(s->xram, sdev->reg_addrs[1].reg_size); | ||
754 | sbus_iounmap(s->regs, sdev->reg_addrs[2].reg_size); | ||
755 | } | ||
756 | sbus_free_consistent(sdev, | ||
757 | (SOC_CQ_REQ0_SIZE+SOC_CQ_REQ1_SIZE)*sizeof(soc_req), | ||
758 | s->req_cpu, s->req_dvma); | ||
759 | } | ||
760 | } | ||
761 | |||
762 | module_init(soc_probe); | ||
763 | module_exit(soc_cleanup); | ||
764 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/fc4/soc.h b/drivers/fc4/soc.h deleted file mode 100644 index d38cf5b28eed..000000000000 --- a/drivers/fc4/soc.h +++ /dev/null | |||
@@ -1,301 +0,0 @@ | |||
1 | /* soc.h: Definitions for Sparc SUNW,soc Fibre Channel Sbus driver. | ||
2 | * | ||
3 | * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
4 | */ | ||
5 | |||
6 | #ifndef __SOC_H | ||
7 | #define __SOC_H | ||
8 | |||
9 | #include "fc.h" | ||
10 | #include "fcp.h" | ||
11 | #include "fcp_impl.h" | ||
12 | |||
13 | /* Hardware register offsets and constants first {{{ */ | ||
14 | #define CFG 0x00UL /* Config Register */ | ||
15 | #define SAE 0x04UL /* Slave Access Error Register */ | ||
16 | #define CMD 0x08UL /* Command and Status Register */ | ||
17 | #define IMASK 0x0cUL /* Interrupt Mask Register */ | ||
18 | |||
19 | /* Config Register */ | ||
20 | #define SOC_CFG_EXT_RAM_BANK_MASK 0x07000000 | ||
21 | #define SOC_CFG_EEPROM_BANK_MASK 0x00030000 | ||
22 | #define SOC_CFG_BURST64_MASK 0x00000700 | ||
23 | #define SOC_CFG_SBUS_PARITY_TEST 0x00000020 | ||
24 | #define SOC_CFG_SBUS_PARITY_CHECK 0x00000010 | ||
25 | #define SOC_CFG_SBUS_ENHANCED 0x00000008 | ||
26 | #define SOC_CFG_BURST_MASK 0x00000007 | ||
27 | /* Bursts */ | ||
28 | #define SOC_CFG_BURST_4 0x00000000 | ||
29 | #define SOC_CFG_BURST_16 0x00000004 | ||
30 | #define SOC_CFG_BURST_32 0x00000005 | ||
31 | #define SOC_CFG_BURST_64 0x00000006 | ||
32 | |||
33 | /* Slave Access Error Register */ | ||
34 | #define SOC_SAE_ALIGNMENT 0x00000004 | ||
35 | #define SOC_SAE_UNSUPPORTED 0x00000002 | ||
36 | #define SOC_SAE_PARITY 0x00000001 | ||
37 | |||
38 | /* Command & Status Register */ | ||
39 | #define SOC_CMD_RSP_QALL 0x000f0000 | ||
40 | #define SOC_CMD_RSP_Q0 0x00010000 | ||
41 | #define SOC_CMD_RSP_Q1 0x00020000 | ||
42 | #define SOC_CMD_RSP_Q2 0x00040000 | ||
43 | #define SOC_CMD_RSP_Q3 0x00080000 | ||
44 | #define SOC_CMD_REQ_QALL 0x00000f00 | ||
45 | #define SOC_CMD_REQ_Q0 0x00000100 | ||
46 | #define SOC_CMD_REQ_Q1 0x00000200 | ||
47 | #define SOC_CMD_REQ_Q2 0x00000400 | ||
48 | #define SOC_CMD_REQ_Q3 0x00000800 | ||
49 | #define SOC_CMD_SAE 0x00000080 | ||
50 | #define SOC_CMD_INTR_PENDING 0x00000008 | ||
51 | #define SOC_CMD_NON_QUEUED 0x00000004 | ||
52 | #define SOC_CMD_IDLE 0x00000002 | ||
53 | #define SOC_CMD_SOFT_RESET 0x00000001 | ||
54 | |||
55 | /* Interrupt Mask Register */ | ||
56 | #define SOC_IMASK_RSP_QALL 0x000f0000 | ||
57 | #define SOC_IMASK_RSP_Q0 0x00010000 | ||
58 | #define SOC_IMASK_RSP_Q1 0x00020000 | ||
59 | #define SOC_IMASK_RSP_Q2 0x00040000 | ||
60 | #define SOC_IMASK_RSP_Q3 0x00080000 | ||
61 | #define SOC_IMASK_REQ_QALL 0x00000f00 | ||
62 | #define SOC_IMASK_REQ_Q0 0x00000100 | ||
63 | #define SOC_IMASK_REQ_Q1 0x00000200 | ||
64 | #define SOC_IMASK_REQ_Q2 0x00000400 | ||
65 | #define SOC_IMASK_REQ_Q3 0x00000800 | ||
66 | #define SOC_IMASK_SAE 0x00000080 | ||
67 | #define SOC_IMASK_NON_QUEUED 0x00000004 | ||
68 | |||
69 | #define SOC_INTR(s, cmd) \ | ||
70 | (((cmd & SOC_CMD_RSP_QALL) | ((~cmd) & SOC_CMD_REQ_QALL)) \ | ||
71 | & s->imask) | ||
72 | |||
73 | #define SOC_SETIMASK(s, i) \ | ||
74 | do { (s)->imask = (i); \ | ||
75 | sbus_writel((i), (s)->regs + IMASK); \ | ||
76 | } while(0) | ||
77 | |||
78 | /* XRAM | ||
79 | * | ||
80 | * This is a 64KB register area. It accepts only halfword access. | ||
81 | * That's why here are the following inline functions... | ||
82 | */ | ||
83 | |||
84 | typedef void __iomem *xram_p; | ||
85 | |||
86 | /* Get 32bit number from XRAM */ | ||
87 | static inline u32 xram_get_32(xram_p x) | ||
88 | { | ||
89 | return ((sbus_readw(x + 0x00UL) << 16) | | ||
90 | (sbus_readw(x + 0x02UL))); | ||
91 | } | ||
92 | |||
93 | /* Like the above, but when we don't care about the high 16 bits */ | ||
94 | static inline u32 xram_get_32low(xram_p x) | ||
95 | { | ||
96 | return (u32) sbus_readw(x + 0x02UL); | ||
97 | } | ||
98 | |||
99 | static inline u16 xram_get_16(xram_p x) | ||
100 | { | ||
101 | return sbus_readw(x); | ||
102 | } | ||
103 | |||
104 | static inline u8 xram_get_8(xram_p x) | ||
105 | { | ||
106 | if ((unsigned long)x & 0x1UL) { | ||
107 | x = x - 1; | ||
108 | return (u8) sbus_readw(x); | ||
109 | } else { | ||
110 | return (u8) (sbus_readw(x) >> 8); | ||
111 | } | ||
112 | } | ||
113 | |||
114 | static inline void xram_copy_from(void *p, xram_p x, int len) | ||
115 | { | ||
116 | for (len >>= 2; len > 0; len--, x += sizeof(u32)) { | ||
117 | u32 val, *p32 = p; | ||
118 | |||
119 | val = ((sbus_readw(x + 0x00UL) << 16) | | ||
120 | (sbus_readw(x + 0x02UL))); | ||
121 | *p32++ = val; | ||
122 | p = p32; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static inline void xram_copy_to(xram_p x, void *p, int len) | ||
127 | { | ||
128 | for (len >>= 2; len > 0; len--, x += sizeof(u32)) { | ||
129 | u32 tmp, *p32 = p; | ||
130 | |||
131 | tmp = *p32++; | ||
132 | p = p32; | ||
133 | sbus_writew(tmp >> 16, x + 0x00UL); | ||
134 | sbus_writew(tmp, x + 0x02UL); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | static inline void xram_bzero(xram_p x, int len) | ||
139 | { | ||
140 | for (len >>= 1; len > 0; len--, x += sizeof(u16)) | ||
141 | sbus_writew(0, x); | ||
142 | } | ||
143 | |||
144 | /* Circular Queue */ | ||
145 | |||
146 | #define SOC_CQ_REQ_OFFSET (0x100 * sizeof(u16)) | ||
147 | #define SOC_CQ_RSP_OFFSET (0x110 * sizeof(u16)) | ||
148 | |||
149 | typedef struct { | ||
150 | u32 address; | ||
151 | u8 in; | ||
152 | u8 out; | ||
153 | u8 last; | ||
154 | u8 seqno; | ||
155 | } soc_hw_cq; | ||
156 | |||
157 | #define SOC_PORT_A 0x0000 /* From/To Port A */ | ||
158 | #define SOC_PORT_B 0x0001 /* From/To Port A */ | ||
159 | #define SOC_FC_HDR 0x0002 /* Contains FC Header */ | ||
160 | #define SOC_NORSP 0x0004 /* Don't generate response nor interrupt */ | ||
161 | #define SOC_NOINT 0x0008 /* Generate response but not interrupt */ | ||
162 | #define SOC_XFERRDY 0x0010 /* Generate XFERRDY */ | ||
163 | #define SOC_IGNOREPARAM 0x0020 /* Ignore PARAM field in the FC header */ | ||
164 | #define SOC_COMPLETE 0x0040 /* Command completed */ | ||
165 | #define SOC_UNSOLICITED 0x0080 /* For request this is the packet to establish unsolicited pools, */ | ||
166 | /* for rsp this is unsolicited packet */ | ||
167 | #define SOC_STATUS 0x0100 /* State change (on/off line) */ | ||
168 | |||
169 | typedef struct { | ||
170 | u32 token; | ||
171 | u16 flags; | ||
172 | u8 class; | ||
173 | u8 segcnt; | ||
174 | u32 bytecnt; | ||
175 | } soc_hdr; | ||
176 | |||
177 | typedef struct { | ||
178 | u32 base; | ||
179 | u32 count; | ||
180 | } soc_data; | ||
181 | |||
182 | #define SOC_CQTYPE_OUTBOUND 0x01 | ||
183 | #define SOC_CQTYPE_INBOUND 0x02 | ||
184 | #define SOC_CQTYPE_SIMPLE 0x03 | ||
185 | #define SOC_CQTYPE_IO_WRITE 0x04 | ||
186 | #define SOC_CQTYPE_IO_READ 0x05 | ||
187 | #define SOC_CQTYPE_UNSOLICITED 0x06 | ||
188 | #define SOC_CQTYPE_DIAG 0x07 | ||
189 | #define SOC_CQTYPE_OFFLINE 0x08 | ||
190 | #define SOC_CQTYPE_RESPONSE 0x10 | ||
191 | #define SOC_CQTYPE_INLINE 0x20 | ||
192 | |||
193 | #define SOC_CQFLAGS_CONT 0x01 | ||
194 | #define SOC_CQFLAGS_FULL 0x02 | ||
195 | #define SOC_CQFLAGS_BADHDR 0x04 | ||
196 | #define SOC_CQFLAGS_BADPKT 0x08 | ||
197 | |||
198 | typedef struct { | ||
199 | soc_hdr shdr; | ||
200 | soc_data data[3]; | ||
201 | fc_hdr fchdr; | ||
202 | u8 count; | ||
203 | u8 type; | ||
204 | u8 flags; | ||
205 | u8 seqno; | ||
206 | } soc_req; | ||
207 | |||
208 | #define SOC_OK 0 | ||
209 | #define SOC_P_RJT 2 | ||
210 | #define SOC_F_RJT 3 | ||
211 | #define SOC_P_BSY 4 | ||
212 | #define SOC_F_BSY 5 | ||
213 | #define SOC_ONLINE 0x10 | ||
214 | #define SOC_OFFLINE 0x11 | ||
215 | #define SOC_TIMEOUT 0x12 | ||
216 | #define SOC_OVERRUN 0x13 | ||
217 | #define SOC_UNKOWN_CQ_TYPE 0x20 | ||
218 | #define SOC_BAD_SEG_CNT 0x21 | ||
219 | #define SOC_MAX_XCHG_EXCEEDED 0x22 | ||
220 | #define SOC_BAD_XID 0x23 | ||
221 | #define SOC_XCHG_BUSY 0x24 | ||
222 | #define SOC_BAD_POOL_ID 0x25 | ||
223 | #define SOC_INSUFFICIENT_CQES 0x26 | ||
224 | #define SOC_ALLOC_FAIL 0x27 | ||
225 | #define SOC_BAD_SID 0x28 | ||
226 | #define SOC_NO_SEG_INIT 0x29 | ||
227 | |||
228 | typedef struct { | ||
229 | soc_hdr shdr; | ||
230 | u32 status; | ||
231 | soc_data data; | ||
232 | u8 xxx1[12]; | ||
233 | fc_hdr fchdr; | ||
234 | u8 count; | ||
235 | u8 type; | ||
236 | u8 flags; | ||
237 | u8 seqno; | ||
238 | } soc_rsp; | ||
239 | |||
240 | /* }}} */ | ||
241 | |||
242 | /* Now our software structures and constants we use to drive the beast {{{ */ | ||
243 | |||
244 | #define SOC_CQ_REQ0_SIZE 4 | ||
245 | #define SOC_CQ_REQ1_SIZE 64 | ||
246 | #define SOC_CQ_RSP0_SIZE 8 | ||
247 | #define SOC_CQ_RSP1_SIZE 4 | ||
248 | |||
249 | #define SOC_SOLICITED_RSP_Q 0 | ||
250 | #define SOC_UNSOLICITED_RSP_Q 1 | ||
251 | |||
252 | struct soc; | ||
253 | |||
254 | typedef struct { | ||
255 | /* This must come first */ | ||
256 | fc_channel fc; | ||
257 | struct soc *s; | ||
258 | u16 flags; | ||
259 | u16 mask; | ||
260 | } soc_port; | ||
261 | |||
262 | typedef struct { | ||
263 | soc_hw_cq __iomem *hw_cq; /* Related XRAM cq */ | ||
264 | soc_req __iomem *pool; | ||
265 | u8 in; | ||
266 | u8 out; | ||
267 | u8 last; | ||
268 | u8 seqno; | ||
269 | } soc_cq_rsp; | ||
270 | |||
271 | typedef struct { | ||
272 | soc_hw_cq __iomem *hw_cq; /* Related XRAM cq */ | ||
273 | soc_req *pool; | ||
274 | u8 in; | ||
275 | u8 out; | ||
276 | u8 last; | ||
277 | u8 seqno; | ||
278 | } soc_cq_req; | ||
279 | |||
280 | struct soc { | ||
281 | spinlock_t lock; | ||
282 | soc_port port[2]; /* Every SOC has one or two FC ports */ | ||
283 | soc_cq_req req[2]; /* Request CQs */ | ||
284 | soc_cq_rsp rsp[2]; /* Response CQs */ | ||
285 | int soc_no; | ||
286 | void __iomem *regs; | ||
287 | xram_p xram; | ||
288 | fc_wwn wwn; | ||
289 | u32 imask; /* Our copy of regs->imask */ | ||
290 | u32 cfg; /* Our copy of regs->cfg */ | ||
291 | char serv_params[80]; | ||
292 | struct soc *next; | ||
293 | int curr_port; /* Which port will have priority to fcp_queue_empty */ | ||
294 | |||
295 | soc_req *req_cpu; | ||
296 | u32 req_dvma; | ||
297 | }; | ||
298 | |||
299 | /* }}} */ | ||
300 | |||
301 | #endif /* !(__SOC_H) */ | ||
diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c deleted file mode 100644 index c903ebfab526..000000000000 --- a/drivers/fc4/socal.c +++ /dev/null | |||
@@ -1,904 +0,0 @@ | |||
1 | /* socal.c: Sparc SUNW,socal (SOC+) Fibre Channel Sbus adapter support. | ||
2 | * | ||
3 | * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz) | ||
4 | * | ||
5 | * Sources: | ||
6 | * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994 | ||
7 | * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995 | ||
8 | * SOC+ Programming Guide 0.1 | ||
9 | * Fibre Channel Arbitrated Loop (FC-AL), dpANS rev. 4.5, 1995 | ||
10 | * | ||
11 | * Supported hardware: | ||
12 | * On-board SOC+ adapters of Ultra Enterprise servers and sun4d. | ||
13 | */ | ||
14 | |||
15 | static char *version = | ||
16 | "socal.c: SOC+ driver v1.1 9/Feb/99 Jakub Jelinek (jj@ultra.linux.cz)\n"; | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/fcntl.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/ptrace.h> | ||
24 | #include <linux/ioport.h> | ||
25 | #include <linux/in.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/bitops.h> | ||
30 | #include <asm/system.h> | ||
31 | #include <asm/io.h> | ||
32 | #include <asm/dma.h> | ||
33 | #include <linux/errno.h> | ||
34 | #include <asm/byteorder.h> | ||
35 | |||
36 | #include <asm/openprom.h> | ||
37 | #include <asm/oplib.h> | ||
38 | #include <asm/pgtable.h> | ||
39 | #include <asm/irq.h> | ||
40 | |||
41 | /* #define SOCALDEBUG */ | ||
42 | /* #define HAVE_SOCAL_UCODE */ | ||
43 | /* #define USE_64BIT_MODE */ | ||
44 | |||
45 | #include "fcp_impl.h" | ||
46 | #include "socal.h" | ||
47 | #ifdef HAVE_SOCAL_UCODE | ||
48 | #include "socal_asm.h" | ||
49 | #endif | ||
50 | |||
51 | #define socal_printk printk ("socal%d: ", s->socal_no); printk | ||
52 | |||
53 | #ifdef SOCALDEBUG | ||
54 | #define SOD(x) socal_printk x; | ||
55 | #else | ||
56 | #define SOD(x) | ||
57 | #endif | ||
58 | |||
59 | #define for_each_socal(s) for (s = socals; s; s = s->next) | ||
60 | struct socal *socals = NULL; | ||
61 | |||
62 | static void socal_copy_from_xram(void *d, void __iomem *xram, long size) | ||
63 | { | ||
64 | u32 *dp = (u32 *) d; | ||
65 | while (size) { | ||
66 | *dp++ = sbus_readl(xram); | ||
67 | xram += sizeof(u32); | ||
68 | size -= sizeof(u32); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | static void socal_copy_to_xram(void __iomem *xram, void *s, long size) | ||
73 | { | ||
74 | u32 *sp = (u32 *) s; | ||
75 | while (size) { | ||
76 | u32 val = *sp++; | ||
77 | sbus_writel(val, xram); | ||
78 | xram += sizeof(u32); | ||
79 | size -= sizeof(u32); | ||
80 | } | ||
81 | } | ||
82 | |||
83 | #ifdef HAVE_SOCAL_UCODE | ||
84 | static void socal_bzero(unsigned long xram, int size) | ||
85 | { | ||
86 | while (size) { | ||
87 | sbus_writel(0, xram); | ||
88 | xram += sizeof(u32); | ||
89 | size -= sizeof(u32); | ||
90 | } | ||
91 | } | ||
92 | #endif | ||
93 | |||
94 | static inline void socal_disable(struct socal *s) | ||
95 | { | ||
96 | sbus_writel(0, s->regs + IMASK); | ||
97 | sbus_writel(SOCAL_CMD_SOFT_RESET, s->regs + CMD); | ||
98 | } | ||
99 | |||
100 | static inline void socal_enable(struct socal *s) | ||
101 | { | ||
102 | SOD(("enable %08x\n", s->cfg)) | ||
103 | sbus_writel(0, s->regs + SAE); | ||
104 | sbus_writel(s->cfg, s->regs + CFG); | ||
105 | sbus_writel(SOCAL_CMD_RSP_QALL, s->regs + CMD); | ||
106 | SOCAL_SETIMASK(s, SOCAL_IMASK_RSP_QALL | SOCAL_IMASK_SAE); | ||
107 | SOD(("imask %08x %08x\n", s->imask, sbus_readl(s->regs + IMASK))); | ||
108 | } | ||
109 | |||
110 | static void socal_reset(fc_channel *fc) | ||
111 | { | ||
112 | socal_port *port = (socal_port *)fc; | ||
113 | struct socal *s = port->s; | ||
114 | |||
115 | /* FIXME */ | ||
116 | socal_disable(s); | ||
117 | s->req[0].seqno = 1; | ||
118 | s->req[1].seqno = 1; | ||
119 | s->rsp[0].seqno = 1; | ||
120 | s->rsp[1].seqno = 1; | ||
121 | s->req[0].in = 0; | ||
122 | s->req[1].in = 0; | ||
123 | s->rsp[0].in = 0; | ||
124 | s->rsp[1].in = 0; | ||
125 | s->req[0].out = 0; | ||
126 | s->req[1].out = 0; | ||
127 | s->rsp[0].out = 0; | ||
128 | s->rsp[1].out = 0; | ||
129 | |||
130 | /* FIXME */ | ||
131 | socal_enable(s); | ||
132 | } | ||
133 | |||
134 | static inline void socal_solicited(struct socal *s, unsigned long qno) | ||
135 | { | ||
136 | socal_rsp *hwrsp; | ||
137 | socal_cq *sw_cq; | ||
138 | int token; | ||
139 | int status; | ||
140 | fc_channel *fc; | ||
141 | |||
142 | sw_cq = &s->rsp[qno]; | ||
143 | |||
144 | /* Finally an improvement against old SOC :) */ | ||
145 | sw_cq->in = sbus_readb(s->regs + RESP + qno); | ||
146 | SOD (("socal_solicited, %d packets arrived\n", | ||
147 | (sw_cq->in - sw_cq->out) & sw_cq->last)) | ||
148 | for (;;) { | ||
149 | hwrsp = (socal_rsp *)sw_cq->pool + sw_cq->out; | ||
150 | SOD(("hwrsp %p out %d\n", hwrsp, sw_cq->out)) | ||
151 | |||
152 | #if defined(SOCALDEBUG) && 0 | ||
153 | { | ||
154 | u32 *u = (u32 *)hwrsp; | ||
155 | SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", | ||
156 | u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) | ||
157 | u += 8; | ||
158 | SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", | ||
159 | u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) | ||
160 | u = (u32 *)s->xram; | ||
161 | while (u < ((u32 *)s->regs)) { | ||
162 | if (sbus_readl(&u[0]) == 0x00003000 || | ||
163 | sbus_readl(&u[0]) == 0x00003801) { | ||
164 | SOD(("Found at %04lx\n", | ||
165 | (unsigned long)u - (unsigned long)s->xram)) | ||
166 | SOD((" %08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", | ||
167 | sbus_readl(&u[0]), sbus_readl(&u[1]), | ||
168 | sbus_readl(&u[2]), sbus_readl(&u[3]), | ||
169 | sbus_readl(&u[4]), sbus_readl(&u[5]), | ||
170 | sbus_readl(&u[6]), sbus_readl(&u[7]))) | ||
171 | u += 8; | ||
172 | SOD((" %08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", | ||
173 | sbus_readl(&u[0]), sbus_readl(&u[1]), | ||
174 | sbus_readl(&u[2]), sbus_readl(&u[3]), | ||
175 | sbus_readl(&u[4]), sbus_readl(&u[5]), | ||
176 | sbus_readl(&u[6]), sbus_readl(&u[7]))) | ||
177 | u -= 8; | ||
178 | } | ||
179 | u++; | ||
180 | } | ||
181 | } | ||
182 | #endif | ||
183 | |||
184 | token = hwrsp->shdr.token; | ||
185 | status = hwrsp->status; | ||
186 | fc = (fc_channel *)(&s->port[(token >> 11) & 1]); | ||
187 | |||
188 | SOD(("Solicited token %08x status %08x\n", token, status)) | ||
189 | if (status == SOCAL_OK) { | ||
190 | fcp_receive_solicited(fc, token >> 12, | ||
191 | token & ((1 << 11) - 1), | ||
192 | FC_STATUS_OK, NULL); | ||
193 | } else { | ||
194 | /* We have intentionally defined FC_STATUS_* constants | ||
195 | * to match SOCAL_* constants, otherwise we'd have to | ||
196 | * translate status. | ||
197 | */ | ||
198 | fcp_receive_solicited(fc, token >> 12, | ||
199 | token & ((1 << 11) - 1), status, &hwrsp->fchdr); | ||
200 | } | ||
201 | |||
202 | if (++sw_cq->out > sw_cq->last) { | ||
203 | sw_cq->seqno++; | ||
204 | sw_cq->out = 0; | ||
205 | } | ||
206 | |||
207 | if (sw_cq->out == sw_cq->in) { | ||
208 | sw_cq->in = sbus_readb(s->regs + RESP + qno); | ||
209 | if (sw_cq->out == sw_cq->in) { | ||
210 | /* Tell the hardware about it */ | ||
211 | sbus_writel((sw_cq->out << 24) | | ||
212 | (SOCAL_CMD_RSP_QALL & | ||
213 | ~(SOCAL_CMD_RSP_Q0 << qno)), | ||
214 | s->regs + CMD); | ||
215 | |||
216 | /* Read it, so that we're sure it has been updated */ | ||
217 | sbus_readl(s->regs + CMD); | ||
218 | sw_cq->in = sbus_readb(s->regs + RESP + qno); | ||
219 | if (sw_cq->out == sw_cq->in) | ||
220 | break; | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | |||
226 | static inline void socal_request (struct socal *s, u32 cmd) | ||
227 | { | ||
228 | SOCAL_SETIMASK(s, s->imask & ~(cmd & SOCAL_CMD_REQ_QALL)); | ||
229 | SOD(("imask %08x %08x\n", s->imask, sbus_readl(s->regs + IMASK))); | ||
230 | |||
231 | SOD(("Queues available %08x OUT %X\n", cmd, s->regs->reqpr[0])) | ||
232 | if (s->port[s->curr_port].fc.state != FC_STATE_OFFLINE) { | ||
233 | fcp_queue_empty ((fc_channel *)&(s->port[s->curr_port])); | ||
234 | if (((s->req[1].in + 1) & s->req[1].last) != (s->req[1].out)) | ||
235 | fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); | ||
236 | } else { | ||
237 | fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); | ||
238 | } | ||
239 | if (s->port[1 - s->curr_port].fc.state != FC_STATE_OFFLINE) | ||
240 | s->curr_port ^= 1; | ||
241 | } | ||
242 | |||
243 | static inline void socal_unsolicited (struct socal *s, unsigned long qno) | ||
244 | { | ||
245 | socal_rsp *hwrsp, *hwrspc; | ||
246 | socal_cq *sw_cq; | ||
247 | int count; | ||
248 | int status; | ||
249 | int flags; | ||
250 | fc_channel *fc; | ||
251 | |||
252 | sw_cq = &s->rsp[qno]; | ||
253 | |||
254 | sw_cq->in = sbus_readb(s->regs + RESP + qno); | ||
255 | SOD (("socal_unsolicited, %d packets arrived, in %d\n", | ||
256 | (sw_cq->in - sw_cq->out) & sw_cq->last, sw_cq->in)) | ||
257 | while (sw_cq->in != sw_cq->out) { | ||
258 | /* ...real work per entry here... */ | ||
259 | hwrsp = (socal_rsp *)sw_cq->pool + sw_cq->out; | ||
260 | SOD(("hwrsp %p out %d\n", hwrsp, sw_cq->out)) | ||
261 | |||
262 | #if defined(SOCALDEBUG) && 0 | ||
263 | { | ||
264 | u32 *u = (u32 *)hwrsp; | ||
265 | SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", | ||
266 | u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) | ||
267 | u += 8; | ||
268 | SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", | ||
269 | u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) | ||
270 | } | ||
271 | #endif | ||
272 | |||
273 | hwrspc = NULL; | ||
274 | flags = hwrsp->shdr.flags; | ||
275 | count = hwrsp->count; | ||
276 | fc = (fc_channel *)&s->port[flags & SOCAL_PORT_B]; | ||
277 | SOD(("FC %08lx\n", (long)fc)) | ||
278 | |||
279 | if (count != 1) { | ||
280 | /* Ugh, continuation entries */ | ||
281 | u8 in; | ||
282 | |||
283 | if (count != 2) { | ||
284 | printk("%s: Too many continuations entries %d\n", | ||
285 | fc->name, count); | ||
286 | goto update_out; | ||
287 | } | ||
288 | |||
289 | in = sw_cq->in; | ||
290 | if (in < sw_cq->out) | ||
291 | in += sw_cq->last + 1; | ||
292 | if (in < sw_cq->out + 2) { | ||
293 | /* Ask the hardware if they haven't arrived yet. */ | ||
294 | sbus_writel((sw_cq->out << 24) | | ||
295 | (SOCAL_CMD_RSP_QALL & | ||
296 | ~(SOCAL_CMD_RSP_Q0 << qno)), | ||
297 | s->regs + CMD); | ||
298 | |||
299 | /* Read it, so that we're sure it has been updated */ | ||
300 | sbus_readl(s->regs + CMD); | ||
301 | sw_cq->in = sbus_readb(s->regs + RESP + qno); | ||
302 | in = sw_cq->in; | ||
303 | if (in < sw_cq->out) | ||
304 | in += sw_cq->last + 1; | ||
305 | if (in < sw_cq->out + 2) /* Nothing came, let us wait */ | ||
306 | return; | ||
307 | } | ||
308 | if (sw_cq->out == sw_cq->last) | ||
309 | hwrspc = (socal_rsp *)sw_cq->pool; | ||
310 | else | ||
311 | hwrspc = hwrsp + 1; | ||
312 | } | ||
313 | |||
314 | switch (flags & ~SOCAL_PORT_B) { | ||
315 | case SOCAL_STATUS: | ||
316 | status = hwrsp->status; | ||
317 | switch (status) { | ||
318 | case SOCAL_ONLINE: | ||
319 | SOD(("State change to ONLINE\n")); | ||
320 | fcp_state_change(fc, FC_STATE_ONLINE); | ||
321 | break; | ||
322 | case SOCAL_ONLINE_LOOP: | ||
323 | SOD(("State change to ONLINE_LOOP\n")); | ||
324 | fcp_state_change(fc, FC_STATE_ONLINE); | ||
325 | break; | ||
326 | case SOCAL_OFFLINE: | ||
327 | SOD(("State change to OFFLINE\n")); | ||
328 | fcp_state_change(fc, FC_STATE_OFFLINE); | ||
329 | break; | ||
330 | default: | ||
331 | printk ("%s: Unknown STATUS no %d\n", | ||
332 | fc->name, status); | ||
333 | break; | ||
334 | }; | ||
335 | |||
336 | break; | ||
337 | case (SOCAL_UNSOLICITED|SOCAL_FC_HDR): | ||
338 | { | ||
339 | int r_ctl = *((u8 *)&hwrsp->fchdr); | ||
340 | unsigned len; | ||
341 | |||
342 | if ((r_ctl & 0xf0) == R_CTL_EXTENDED_SVC) { | ||
343 | len = hwrsp->shdr.bytecnt; | ||
344 | if (len < 4 || !hwrspc) { | ||
345 | printk ("%s: Invalid R_CTL %02x " | ||
346 | "continuation entries\n", | ||
347 | fc->name, r_ctl); | ||
348 | } else { | ||
349 | if (len > 60) | ||
350 | len = 60; | ||
351 | if (*(u32 *)hwrspc == LS_DISPLAY) { | ||
352 | int i; | ||
353 | |||
354 | for (i = 4; i < len; i++) | ||
355 | if (((u8 *)hwrspc)[i] == '\n') | ||
356 | ((u8 *)hwrspc)[i] = ' '; | ||
357 | ((u8 *)hwrspc)[len] = 0; | ||
358 | printk ("%s message: %s\n", | ||
359 | fc->name, ((u8 *)hwrspc) + 4); | ||
360 | } else { | ||
361 | printk ("%s: Unknown LS_CMD " | ||
362 | "%08x\n", fc->name, | ||
363 | *(u32 *)hwrspc); | ||
364 | } | ||
365 | } | ||
366 | } else { | ||
367 | printk ("%s: Unsolicited R_CTL %02x " | ||
368 | "not handled\n", fc->name, r_ctl); | ||
369 | } | ||
370 | } | ||
371 | break; | ||
372 | default: | ||
373 | printk ("%s: Unexpected flags %08x\n", fc->name, flags); | ||
374 | break; | ||
375 | }; | ||
376 | update_out: | ||
377 | if (++sw_cq->out > sw_cq->last) { | ||
378 | sw_cq->seqno++; | ||
379 | sw_cq->out = 0; | ||
380 | } | ||
381 | |||
382 | if (hwrspc) { | ||
383 | if (++sw_cq->out > sw_cq->last) { | ||
384 | sw_cq->seqno++; | ||
385 | sw_cq->out = 0; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | if (sw_cq->out == sw_cq->in) { | ||
390 | sw_cq->in = sbus_readb(s->regs + RESP + qno); | ||
391 | if (sw_cq->out == sw_cq->in) { | ||
392 | /* Tell the hardware about it */ | ||
393 | sbus_writel((sw_cq->out << 24) | | ||
394 | (SOCAL_CMD_RSP_QALL & | ||
395 | ~(SOCAL_CMD_RSP_Q0 << qno)), | ||
396 | s->regs + CMD); | ||
397 | |||
398 | /* Read it, so that we're sure it has been updated */ | ||
399 | sbus_readl(s->regs + CMD); | ||
400 | sw_cq->in = sbus_readb(s->regs + RESP + qno); | ||
401 | } | ||
402 | } | ||
403 | } | ||
404 | } | ||
405 | |||
406 | static irqreturn_t socal_intr(int irq, void *dev_id) | ||
407 | { | ||
408 | u32 cmd; | ||
409 | unsigned long flags; | ||
410 | register struct socal *s = (struct socal *)dev_id; | ||
411 | |||
412 | spin_lock_irqsave(&s->lock, flags); | ||
413 | cmd = sbus_readl(s->regs + CMD); | ||
414 | for (; (cmd = SOCAL_INTR (s, cmd)); cmd = sbus_readl(s->regs + CMD)) { | ||
415 | #ifdef SOCALDEBUG | ||
416 | static int cnt = 0; | ||
417 | if (cnt++ < 50) | ||
418 | printk("soc_intr %08x\n", cmd); | ||
419 | #endif | ||
420 | if (cmd & SOCAL_CMD_RSP_Q2) | ||
421 | socal_unsolicited (s, SOCAL_UNSOLICITED_RSP_Q); | ||
422 | if (cmd & SOCAL_CMD_RSP_Q1) | ||
423 | socal_unsolicited (s, SOCAL_SOLICITED_BAD_RSP_Q); | ||
424 | if (cmd & SOCAL_CMD_RSP_Q0) | ||
425 | socal_solicited (s, SOCAL_SOLICITED_RSP_Q); | ||
426 | if (cmd & SOCAL_CMD_REQ_QALL) | ||
427 | socal_request (s, cmd); | ||
428 | } | ||
429 | spin_unlock_irqrestore(&s->lock, flags); | ||
430 | |||
431 | return IRQ_HANDLED; | ||
432 | } | ||
433 | |||
434 | #define TOKEN(proto, port, token) (((proto)<<12)|(token)|(port)) | ||
435 | |||
436 | static int socal_hw_enque (fc_channel *fc, fcp_cmnd *fcmd) | ||
437 | { | ||
438 | socal_port *port = (socal_port *)fc; | ||
439 | struct socal *s = port->s; | ||
440 | unsigned long qno; | ||
441 | socal_cq *sw_cq; | ||
442 | int cq_next_in; | ||
443 | socal_req *request; | ||
444 | fc_hdr *fch; | ||
445 | int i; | ||
446 | |||
447 | if (fcmd->proto == TYPE_SCSI_FCP) | ||
448 | qno = 1; | ||
449 | else | ||
450 | qno = 0; | ||
451 | SOD(("Putting a FCP packet type %d into hw queue %d\n", fcmd->proto, qno)) | ||
452 | if (s->imask & (SOCAL_IMASK_REQ_Q0 << qno)) { | ||
453 | SOD(("EIO %08x\n", s->imask)) | ||
454 | return -EIO; | ||
455 | } | ||
456 | sw_cq = s->req + qno; | ||
457 | cq_next_in = (sw_cq->in + 1) & sw_cq->last; | ||
458 | |||
459 | if (cq_next_in == sw_cq->out && | ||
460 | cq_next_in == (sw_cq->out = sbus_readb(s->regs + REQP + qno))) { | ||
461 | SOD(("%d IN %d OUT %d LAST %d\n", | ||
462 | qno, sw_cq->in, | ||
463 | sw_cq->out, sw_cq->last)) | ||
464 | SOCAL_SETIMASK(s, s->imask | (SOCAL_IMASK_REQ_Q0 << qno)); | ||
465 | SOD(("imask %08x %08x\n", s->imask, sbus_readl(s->regs + IMASK))); | ||
466 | |||
467 | /* If queue is full, just say NO. */ | ||
468 | return -EBUSY; | ||
469 | } | ||
470 | |||
471 | request = sw_cq->pool + sw_cq->in; | ||
472 | fch = &request->fchdr; | ||
473 | |||
474 | switch (fcmd->proto) { | ||
475 | case TYPE_SCSI_FCP: | ||
476 | request->shdr.token = TOKEN(TYPE_SCSI_FCP, port->mask, fcmd->token); | ||
477 | request->data[0].base = fc->dma_scsi_cmd + fcmd->token * sizeof(fcp_cmd); | ||
478 | request->data[0].count = sizeof(fcp_cmd); | ||
479 | request->data[1].base = fc->dma_scsi_rsp + fcmd->token * fc->rsp_size; | ||
480 | request->data[1].count = fc->rsp_size; | ||
481 | if (fcmd->data) { | ||
482 | request->shdr.segcnt = 3; | ||
483 | i = fc->scsi_cmd_pool[fcmd->token].fcp_data_len; | ||
484 | request->shdr.bytecnt = i; | ||
485 | request->data[2].base = fcmd->data; | ||
486 | request->data[2].count = i; | ||
487 | request->type = (fc->scsi_cmd_pool[fcmd->token].fcp_cntl & FCP_CNTL_WRITE) ? | ||
488 | SOCAL_CQTYPE_IO_WRITE : SOCAL_CQTYPE_IO_READ; | ||
489 | } else { | ||
490 | request->shdr.segcnt = 2; | ||
491 | request->shdr.bytecnt = 0; | ||
492 | request->data[2].base = 0; | ||
493 | request->data[2].count = 0; | ||
494 | request->type = SOCAL_CQTYPE_SIMPLE; | ||
495 | } | ||
496 | FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fcmd->did); | ||
497 | FILL_FCHDR_SID(fch, fc->sid); | ||
498 | FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); | ||
499 | FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); | ||
500 | FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); | ||
501 | fch->param = 0; | ||
502 | request->shdr.flags = port->flags; | ||
503 | request->shdr.class = fc->posmap ? 3 : 2; | ||
504 | break; | ||
505 | |||
506 | case PROTO_OFFLINE: | ||
507 | memset (request, 0, sizeof(*request)); | ||
508 | request->shdr.token = TOKEN(PROTO_OFFLINE, port->mask, fcmd->token); | ||
509 | request->type = SOCAL_CQTYPE_OFFLINE; | ||
510 | FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fcmd->did); | ||
511 | FILL_FCHDR_SID(fch, fc->sid); | ||
512 | FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); | ||
513 | FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); | ||
514 | FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); | ||
515 | request->shdr.flags = port->flags; | ||
516 | break; | ||
517 | |||
518 | case PROTO_REPORT_AL_MAP: | ||
519 | memset (request, 0, sizeof(*request)); | ||
520 | request->shdr.token = TOKEN(PROTO_REPORT_AL_MAP, port->mask, fcmd->token); | ||
521 | request->type = SOCAL_CQTYPE_REPORT_MAP; | ||
522 | request->shdr.flags = port->flags; | ||
523 | request->shdr.segcnt = 1; | ||
524 | request->shdr.bytecnt = sizeof(fc_al_posmap); | ||
525 | request->data[0].base = fcmd->cmd; | ||
526 | request->data[0].count = sizeof(fc_al_posmap); | ||
527 | break; | ||
528 | |||
529 | default: | ||
530 | request->shdr.token = TOKEN(fcmd->proto, port->mask, fcmd->token); | ||
531 | request->shdr.class = fc->posmap ? 3 : 2; | ||
532 | request->shdr.flags = port->flags; | ||
533 | memcpy (fch, &fcmd->fch, sizeof(fc_hdr)); | ||
534 | request->data[0].count = fcmd->cmdlen; | ||
535 | request->data[1].count = fcmd->rsplen; | ||
536 | request->type = fcmd->class; | ||
537 | switch (fcmd->class) { | ||
538 | case FC_CLASS_OUTBOUND: | ||
539 | request->data[0].base = fcmd->cmd; | ||
540 | request->data[0].count = fcmd->cmdlen; | ||
541 | request->type = SOCAL_CQTYPE_OUTBOUND; | ||
542 | request->shdr.bytecnt = fcmd->cmdlen; | ||
543 | request->shdr.segcnt = 1; | ||
544 | break; | ||
545 | case FC_CLASS_INBOUND: | ||
546 | request->data[0].base = fcmd->rsp; | ||
547 | request->data[0].count = fcmd->rsplen; | ||
548 | request->type = SOCAL_CQTYPE_INBOUND; | ||
549 | request->shdr.bytecnt = 0; | ||
550 | request->shdr.segcnt = 1; | ||
551 | break; | ||
552 | case FC_CLASS_SIMPLE: | ||
553 | request->data[0].base = fcmd->cmd; | ||
554 | request->data[1].base = fcmd->rsp; | ||
555 | request->data[0].count = fcmd->cmdlen; | ||
556 | request->data[1].count = fcmd->rsplen; | ||
557 | request->type = SOCAL_CQTYPE_SIMPLE; | ||
558 | request->shdr.bytecnt = fcmd->cmdlen; | ||
559 | request->shdr.segcnt = 2; | ||
560 | break; | ||
561 | case FC_CLASS_IO_READ: | ||
562 | case FC_CLASS_IO_WRITE: | ||
563 | request->data[0].base = fcmd->cmd; | ||
564 | request->data[1].base = fcmd->rsp; | ||
565 | request->data[0].count = fcmd->cmdlen; | ||
566 | request->data[1].count = fcmd->rsplen; | ||
567 | request->type = (fcmd->class == FC_CLASS_IO_READ) ? SOCAL_CQTYPE_IO_READ : SOCAL_CQTYPE_IO_WRITE; | ||
568 | if (fcmd->data) { | ||
569 | request->data[2].base = fcmd->data; | ||
570 | request->data[2].count = fcmd->datalen; | ||
571 | request->shdr.bytecnt = fcmd->datalen; | ||
572 | request->shdr.segcnt = 3; | ||
573 | } else { | ||
574 | request->shdr.bytecnt = 0; | ||
575 | request->shdr.segcnt = 2; | ||
576 | } | ||
577 | break; | ||
578 | } | ||
579 | break; | ||
580 | } | ||
581 | |||
582 | request->count = 1; | ||
583 | request->flags = 0; | ||
584 | request->seqno = sw_cq->seqno; | ||
585 | |||
586 | SOD(("queueing token %08x\n", request->shdr.token)) | ||
587 | |||
588 | /* And now tell the SOCAL about it */ | ||
589 | |||
590 | if (++sw_cq->in > sw_cq->last) { | ||
591 | sw_cq->in = 0; | ||
592 | sw_cq->seqno++; | ||
593 | } | ||
594 | |||
595 | SOD(("Putting %08x into cmd\n", SOCAL_CMD_RSP_QALL | (sw_cq->in << 24) | (SOCAL_CMD_REQ_Q0 << qno))) | ||
596 | |||
597 | sbus_writel(SOCAL_CMD_RSP_QALL | (sw_cq->in << 24) | (SOCAL_CMD_REQ_Q0 << qno), | ||
598 | s->regs + CMD); | ||
599 | |||
600 | /* Read so that command is completed */ | ||
601 | sbus_readl(s->regs + CMD); | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static inline void socal_download_fw(struct socal *s) | ||
607 | { | ||
608 | #ifdef HAVE_SOCAL_UCODE | ||
609 | SOD(("Loading %ld bytes from %p to %p\n", sizeof(socal_ucode), socal_ucode, s->xram)) | ||
610 | socal_copy_to_xram(s->xram, socal_ucode, sizeof(socal_ucode)); | ||
611 | SOD(("Clearing the rest of memory\n")) | ||
612 | socal_bzero (s->xram + sizeof(socal_ucode), 65536 - sizeof(socal_ucode)); | ||
613 | SOD(("Done\n")) | ||
614 | #endif | ||
615 | } | ||
616 | |||
617 | /* Check for what the best SBUS burst we can use happens | ||
618 | * to be on this machine. | ||
619 | */ | ||
620 | static inline void socal_init_bursts(struct socal *s, struct sbus_dev *sdev) | ||
621 | { | ||
622 | int bsizes, bsizes_more; | ||
623 | u32 cfg; | ||
624 | |||
625 | bsizes = (prom_getintdefault(sdev->prom_node,"burst-sizes",0xff) & 0xff); | ||
626 | bsizes_more = (prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff) & 0xff); | ||
627 | bsizes &= bsizes_more; | ||
628 | #ifdef USE_64BIT_MODE | ||
629 | #ifdef __sparc_v9__ | ||
630 | mmu_set_sbus64(sdev, bsizes >> 16); | ||
631 | #endif | ||
632 | #endif | ||
633 | if ((bsizes & 0x7f) == 0x7f) | ||
634 | cfg = SOCAL_CFG_BURST_64; | ||
635 | else if ((bsizes & 0x3f) == 0x3f) | ||
636 | cfg = SOCAL_CFG_BURST_32; | ||
637 | else if ((bsizes & 0x1f) == 0x1f) | ||
638 | cfg = SOCAL_CFG_BURST_16; | ||
639 | else | ||
640 | cfg = SOCAL_CFG_BURST_4; | ||
641 | #ifdef USE_64BIT_MODE | ||
642 | #ifdef __sparc_v9__ | ||
643 | /* What is BURST_128? -jj */ | ||
644 | if ((bsizes & 0x780000) == 0x780000) | ||
645 | cfg |= (SOCAL_CFG_BURST_64 << 8) | SOCAL_CFG_SBUS_ENHANCED; | ||
646 | else if ((bsizes & 0x380000) == 0x380000) | ||
647 | cfg |= (SOCAL_CFG_BURST_32 << 8) | SOCAL_CFG_SBUS_ENHANCED; | ||
648 | else if ((bsizes & 0x180000) == 0x180000) | ||
649 | cfg |= (SOCAL_CFG_BURST_16 << 8) | SOCAL_CFG_SBUS_ENHANCED; | ||
650 | else | ||
651 | cfg |= (SOCAL_CFG_BURST_8 << 8) | SOCAL_CFG_SBUS_ENHANCED; | ||
652 | #endif | ||
653 | #endif | ||
654 | s->cfg = cfg; | ||
655 | } | ||
656 | |||
657 | static inline void socal_init(struct sbus_dev *sdev, int no) | ||
658 | { | ||
659 | unsigned char tmp[60]; | ||
660 | int propl; | ||
661 | struct socal *s; | ||
662 | static unsigned version_printed = 0; | ||
663 | socal_hw_cq cq[8]; | ||
664 | int size, i; | ||
665 | int irq, node; | ||
666 | |||
667 | s = kzalloc (sizeof (struct socal), GFP_KERNEL); | ||
668 | if (!s) return; | ||
669 | spin_lock_init(&s->lock); | ||
670 | s->socal_no = no; | ||
671 | |||
672 | SOD(("socals %08lx socal_intr %08lx socal_hw_enque %08lx\n", | ||
673 | (long)socals, (long)socal_intr, (long)socal_hw_enque)) | ||
674 | if (version_printed++ == 0) | ||
675 | printk (version); | ||
676 | |||
677 | s->port[0].fc.module = THIS_MODULE; | ||
678 | s->port[1].fc.module = THIS_MODULE; | ||
679 | |||
680 | s->next = socals; | ||
681 | socals = s; | ||
682 | s->port[0].fc.dev = sdev; | ||
683 | s->port[1].fc.dev = sdev; | ||
684 | s->port[0].s = s; | ||
685 | s->port[1].s = s; | ||
686 | |||
687 | s->port[0].fc.next = &s->port[1].fc; | ||
688 | |||
689 | /* World Wide Name of SOCAL */ | ||
690 | propl = prom_getproperty (sdev->prom_node, "wwn", tmp, sizeof(tmp)); | ||
691 | if (propl != sizeof (fc_wwn)) { | ||
692 | s->wwn.naaid = NAAID_IEEE_REG; | ||
693 | s->wwn.nportid = 0x123; | ||
694 | s->wwn.hi = 0x1234; | ||
695 | s->wwn.lo = 0x12345678; | ||
696 | } else | ||
697 | memcpy (&s->wwn, tmp, sizeof (fc_wwn)); | ||
698 | |||
699 | memcpy (&s->port[0].fc.wwn_nport, &s->wwn, sizeof (fc_wwn)); | ||
700 | s->port[0].fc.wwn_nport.lo++; | ||
701 | memcpy (&s->port[1].fc.wwn_nport, &s->wwn, sizeof (fc_wwn)); | ||
702 | s->port[1].fc.wwn_nport.lo+=2; | ||
703 | |||
704 | node = prom_getchild (sdev->prom_node); | ||
705 | while (node && (node = prom_searchsiblings (node, "sf"))) { | ||
706 | int port; | ||
707 | |||
708 | port = prom_getintdefault(node, "port#", -1); | ||
709 | switch (port) { | ||
710 | case 0: | ||
711 | case 1: | ||
712 | if (prom_getproplen(node, "port-wwn") == sizeof (fc_wwn)) | ||
713 | prom_getproperty (node, "port-wwn", | ||
714 | (char *)&s->port[port].fc.wwn_nport, | ||
715 | sizeof (fc_wwn)); | ||
716 | break; | ||
717 | default: | ||
718 | break; | ||
719 | }; | ||
720 | |||
721 | node = prom_getsibling(node); | ||
722 | } | ||
723 | |||
724 | memcpy (&s->port[0].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); | ||
725 | memcpy (&s->port[1].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); | ||
726 | SOD(("Got wwns %08x%08x ports %08x%08x and %08x%08x\n", | ||
727 | *(u32 *)&s->port[0].fc.wwn_node, s->port[0].fc.wwn_node.lo, | ||
728 | *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, | ||
729 | *(u32 *)&s->port[1].fc.wwn_nport, s->port[1].fc.wwn_nport.lo)) | ||
730 | |||
731 | s->port[0].fc.sid = 1; | ||
732 | s->port[1].fc.sid = 17; | ||
733 | s->port[0].fc.did = 2; | ||
734 | s->port[1].fc.did = 18; | ||
735 | |||
736 | s->port[0].fc.reset = socal_reset; | ||
737 | s->port[1].fc.reset = socal_reset; | ||
738 | |||
739 | if (sdev->num_registers == 1) { | ||
740 | s->eeprom = sbus_ioremap(&sdev->resource[0], 0, | ||
741 | sdev->reg_addrs[0].reg_size, "socal xram"); | ||
742 | if (sdev->reg_addrs[0].reg_size > 0x20000) | ||
743 | s->xram = s->eeprom + 0x10000UL; | ||
744 | else | ||
745 | s->xram = s->eeprom; | ||
746 | s->regs = (s->xram + 0x10000UL); | ||
747 | } else { | ||
748 | /* E.g. starfire presents 3 registers for SOCAL */ | ||
749 | s->xram = sbus_ioremap(&sdev->resource[1], 0, | ||
750 | sdev->reg_addrs[1].reg_size, "socal xram"); | ||
751 | s->regs = sbus_ioremap(&sdev->resource[2], 0, | ||
752 | sdev->reg_addrs[2].reg_size, "socal regs"); | ||
753 | } | ||
754 | |||
755 | socal_init_bursts(s, sdev); | ||
756 | |||
757 | SOD(("Disabling SOCAL\n")) | ||
758 | |||
759 | socal_disable (s); | ||
760 | |||
761 | irq = sdev->irqs[0]; | ||
762 | |||
763 | if (request_irq (irq, socal_intr, IRQF_SHARED, "SOCAL", (void *)s)) { | ||
764 | socal_printk ("Cannot order irq %d to go\n", irq); | ||
765 | socals = s->next; | ||
766 | return; | ||
767 | } | ||
768 | |||
769 | SOD(("SOCAL uses IRQ %d\n", irq)) | ||
770 | |||
771 | s->port[0].fc.irq = irq; | ||
772 | s->port[1].fc.irq = irq; | ||
773 | |||
774 | sprintf (s->port[0].fc.name, "socal%d port A", no); | ||
775 | sprintf (s->port[1].fc.name, "socal%d port B", no); | ||
776 | s->port[0].flags = SOCAL_FC_HDR | SOCAL_PORT_A; | ||
777 | s->port[1].flags = SOCAL_FC_HDR | SOCAL_PORT_B; | ||
778 | s->port[1].mask = (1 << 11); | ||
779 | |||
780 | s->port[0].fc.hw_enque = socal_hw_enque; | ||
781 | s->port[1].fc.hw_enque = socal_hw_enque; | ||
782 | |||
783 | socal_download_fw (s); | ||
784 | |||
785 | SOD(("Downloaded firmware\n")) | ||
786 | |||
787 | /* Now setup xram circular queues */ | ||
788 | memset (cq, 0, sizeof(cq)); | ||
789 | |||
790 | size = (SOCAL_CQ_REQ0_SIZE + SOCAL_CQ_REQ1_SIZE + | ||
791 | SOCAL_CQ_RSP0_SIZE + SOCAL_CQ_RSP1_SIZE + | ||
792 | SOCAL_CQ_RSP2_SIZE) * sizeof(socal_req); | ||
793 | s->req_cpu = sbus_alloc_consistent(sdev, size, &s->req_dvma); | ||
794 | s->req[0].pool = s->req_cpu; | ||
795 | cq[0].address = s->req_dvma; | ||
796 | s->req[1].pool = s->req[0].pool + SOCAL_CQ_REQ0_SIZE; | ||
797 | s->rsp[0].pool = s->req[1].pool + SOCAL_CQ_REQ1_SIZE; | ||
798 | s->rsp[1].pool = s->rsp[0].pool + SOCAL_CQ_RSP0_SIZE; | ||
799 | s->rsp[2].pool = s->rsp[1].pool + SOCAL_CQ_RSP1_SIZE; | ||
800 | |||
801 | s->req[0].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_REQ_OFFSET); | ||
802 | s->req[1].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_REQ_OFFSET + sizeof(socal_hw_cq)); | ||
803 | s->rsp[0].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_RSP_OFFSET); | ||
804 | s->rsp[1].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_RSP_OFFSET + sizeof(socal_hw_cq)); | ||
805 | s->rsp[2].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_RSP_OFFSET + 2 * sizeof(socal_hw_cq)); | ||
806 | |||
807 | cq[1].address = cq[0].address + (SOCAL_CQ_REQ0_SIZE * sizeof(socal_req)); | ||
808 | cq[4].address = cq[1].address + (SOCAL_CQ_REQ1_SIZE * sizeof(socal_req)); | ||
809 | cq[5].address = cq[4].address + (SOCAL_CQ_RSP0_SIZE * sizeof(socal_req)); | ||
810 | cq[6].address = cq[5].address + (SOCAL_CQ_RSP1_SIZE * sizeof(socal_req)); | ||
811 | |||
812 | cq[0].last = SOCAL_CQ_REQ0_SIZE - 1; | ||
813 | cq[1].last = SOCAL_CQ_REQ1_SIZE - 1; | ||
814 | cq[4].last = SOCAL_CQ_RSP0_SIZE - 1; | ||
815 | cq[5].last = SOCAL_CQ_RSP1_SIZE - 1; | ||
816 | cq[6].last = SOCAL_CQ_RSP2_SIZE - 1; | ||
817 | for (i = 0; i < 8; i++) | ||
818 | cq[i].seqno = 1; | ||
819 | |||
820 | s->req[0].last = SOCAL_CQ_REQ0_SIZE - 1; | ||
821 | s->req[1].last = SOCAL_CQ_REQ1_SIZE - 1; | ||
822 | s->rsp[0].last = SOCAL_CQ_RSP0_SIZE - 1; | ||
823 | s->rsp[1].last = SOCAL_CQ_RSP1_SIZE - 1; | ||
824 | s->rsp[2].last = SOCAL_CQ_RSP2_SIZE - 1; | ||
825 | |||
826 | s->req[0].seqno = 1; | ||
827 | s->req[1].seqno = 1; | ||
828 | s->rsp[0].seqno = 1; | ||
829 | s->rsp[1].seqno = 1; | ||
830 | s->rsp[2].seqno = 1; | ||
831 | |||
832 | socal_copy_to_xram(s->xram + SOCAL_CQ_REQ_OFFSET, cq, sizeof(cq)); | ||
833 | |||
834 | SOD(("Setting up params\n")) | ||
835 | |||
836 | /* Make our sw copy of SOCAL service parameters */ | ||
837 | socal_copy_from_xram(s->serv_params, s->xram + 0x280, sizeof (s->serv_params)); | ||
838 | |||
839 | s->port[0].fc.common_svc = (common_svc_parm *)s->serv_params; | ||
840 | s->port[0].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20); | ||
841 | s->port[1].fc.common_svc = (common_svc_parm *)&s->serv_params; | ||
842 | s->port[1].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20); | ||
843 | |||
844 | socal_enable (s); | ||
845 | |||
846 | SOD(("Enabled SOCAL\n")) | ||
847 | } | ||
848 | |||
849 | static int __init socal_probe(void) | ||
850 | { | ||
851 | struct sbus_bus *sbus; | ||
852 | struct sbus_dev *sdev = NULL; | ||
853 | struct socal *s; | ||
854 | int cards = 0; | ||
855 | |||
856 | for_each_sbus(sbus) { | ||
857 | for_each_sbusdev(sdev, sbus) { | ||
858 | if(!strcmp(sdev->prom_name, "SUNW,socal")) { | ||
859 | socal_init(sdev, cards); | ||
860 | cards++; | ||
861 | } | ||
862 | } | ||
863 | } | ||
864 | if (!cards) | ||
865 | return -EIO; | ||
866 | |||
867 | for_each_socal(s) | ||
868 | if (s->next) | ||
869 | s->port[1].fc.next = &s->next->port[0].fc; | ||
870 | |||
871 | fcp_init (&socals->port[0].fc); | ||
872 | return 0; | ||
873 | } | ||
874 | |||
875 | static void __exit socal_cleanup(void) | ||
876 | { | ||
877 | struct socal *s; | ||
878 | int irq; | ||
879 | struct sbus_dev *sdev; | ||
880 | |||
881 | for_each_socal(s) { | ||
882 | irq = s->port[0].fc.irq; | ||
883 | free_irq (irq, s); | ||
884 | |||
885 | fcp_release(&(s->port[0].fc), 2); | ||
886 | |||
887 | sdev = s->port[0].fc.dev; | ||
888 | if (sdev->num_registers == 1) { | ||
889 | sbus_iounmap(s->eeprom, sdev->reg_addrs[0].reg_size); | ||
890 | } else { | ||
891 | sbus_iounmap(s->xram, sdev->reg_addrs[1].reg_size); | ||
892 | sbus_iounmap(s->regs, sdev->reg_addrs[2].reg_size); | ||
893 | } | ||
894 | sbus_free_consistent(sdev, | ||
895 | (SOCAL_CQ_REQ0_SIZE + SOCAL_CQ_REQ1_SIZE + | ||
896 | SOCAL_CQ_RSP0_SIZE + SOCAL_CQ_RSP1_SIZE + | ||
897 | SOCAL_CQ_RSP2_SIZE) * sizeof(socal_req), | ||
898 | s->req_cpu, s->req_dvma); | ||
899 | } | ||
900 | } | ||
901 | |||
902 | module_init(socal_probe); | ||
903 | module_exit(socal_cleanup); | ||
904 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/fc4/socal.h b/drivers/fc4/socal.h deleted file mode 100644 index 774edf68e4d2..000000000000 --- a/drivers/fc4/socal.h +++ /dev/null | |||
@@ -1,314 +0,0 @@ | |||
1 | /* socal.h: Definitions for Sparc SUNW,socal (SOC+) Fibre Channel Sbus driver. | ||
2 | * | ||
3 | * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz) | ||
4 | */ | ||
5 | |||
6 | #ifndef __SOCAL_H | ||
7 | #define __SOCAL_H | ||
8 | |||
9 | #include "fc.h" | ||
10 | #include "fcp.h" | ||
11 | #include "fcp_impl.h" | ||
12 | |||
13 | /* Hardware register offsets and constants first {{{ */ | ||
14 | #define CFG 0x00UL | ||
15 | #define SAE 0x04UL | ||
16 | #define CMD 0x08UL | ||
17 | #define IMASK 0x0cUL | ||
18 | #define REQP 0x10UL | ||
19 | #define RESP 0x14UL | ||
20 | |||
21 | /* Config Register */ | ||
22 | #define SOCAL_CFG_EXT_RAM_BANK_MASK 0x07000000 | ||
23 | #define SOCAL_CFG_EEPROM_BANK_MASK 0x00030000 | ||
24 | #define SOCAL_CFG_BURST64_MASK 0x00000700 | ||
25 | #define SOCAL_CFG_SBUS_PARITY_TEST 0x00000020 | ||
26 | #define SOCAL_CFG_SBUS_PARITY_CHECK 0x00000010 | ||
27 | #define SOCAL_CFG_SBUS_ENHANCED 0x00000008 | ||
28 | #define SOCAL_CFG_BURST_MASK 0x00000007 | ||
29 | /* Bursts */ | ||
30 | #define SOCAL_CFG_BURST_4 0x00000000 | ||
31 | #define SOCAL_CFG_BURST_8 0x00000003 | ||
32 | #define SOCAL_CFG_BURST_16 0x00000004 | ||
33 | #define SOCAL_CFG_BURST_32 0x00000005 | ||
34 | #define SOCAL_CFG_BURST_64 0x00000006 | ||
35 | #define SOCAL_CFG_BURST_128 0x00000007 | ||
36 | |||
37 | /* Slave Access Error Register */ | ||
38 | #define SOCAL_SAE_ALIGNMENT 0x00000004 | ||
39 | #define SOCAL_SAE_UNSUPPORTED 0x00000002 | ||
40 | #define SOCAL_SAE_PARITY 0x00000001 | ||
41 | |||
42 | /* Command & Status Register */ | ||
43 | #define SOCAL_CMD_RSP_QALL 0x000f0000 | ||
44 | #define SOCAL_CMD_RSP_Q0 0x00010000 | ||
45 | #define SOCAL_CMD_RSP_Q1 0x00020000 | ||
46 | #define SOCAL_CMD_RSP_Q2 0x00040000 | ||
47 | #define SOCAL_CMD_RSP_Q3 0x00080000 | ||
48 | #define SOCAL_CMD_REQ_QALL 0x00000f00 | ||
49 | #define SOCAL_CMD_REQ_Q0 0x00000100 | ||
50 | #define SOCAL_CMD_REQ_Q1 0x00000200 | ||
51 | #define SOCAL_CMD_REQ_Q2 0x00000400 | ||
52 | #define SOCAL_CMD_REQ_Q3 0x00000800 | ||
53 | #define SOCAL_CMD_SAE 0x00000080 | ||
54 | #define SOCAL_CMD_INTR_PENDING 0x00000008 | ||
55 | #define SOCAL_CMD_NON_QUEUED 0x00000004 | ||
56 | #define SOCAL_CMD_IDLE 0x00000002 | ||
57 | #define SOCAL_CMD_SOFT_RESET 0x00000001 | ||
58 | |||
59 | /* Interrupt Mask Register */ | ||
60 | #define SOCAL_IMASK_RSP_QALL 0x000f0000 | ||
61 | #define SOCAL_IMASK_RSP_Q0 0x00010000 | ||
62 | #define SOCAL_IMASK_RSP_Q1 0x00020000 | ||
63 | #define SOCAL_IMASK_RSP_Q2 0x00040000 | ||
64 | #define SOCAL_IMASK_RSP_Q3 0x00080000 | ||
65 | #define SOCAL_IMASK_REQ_QALL 0x00000f00 | ||
66 | #define SOCAL_IMASK_REQ_Q0 0x00000100 | ||
67 | #define SOCAL_IMASK_REQ_Q1 0x00000200 | ||
68 | #define SOCAL_IMASK_REQ_Q2 0x00000400 | ||
69 | #define SOCAL_IMASK_REQ_Q3 0x00000800 | ||
70 | #define SOCAL_IMASK_SAE 0x00000080 | ||
71 | #define SOCAL_IMASK_NON_QUEUED 0x00000004 | ||
72 | |||
73 | #define SOCAL_INTR(s, cmd) \ | ||
74 | (((cmd & SOCAL_CMD_RSP_QALL) | ((~cmd) & SOCAL_CMD_REQ_QALL)) \ | ||
75 | & s->imask) | ||
76 | |||
77 | #define SOCAL_SETIMASK(s, i) \ | ||
78 | do { (s)->imask = (i); \ | ||
79 | sbus_writel((i), (s)->regs + IMASK); \ | ||
80 | } while (0) | ||
81 | |||
82 | #define SOCAL_MAX_EXCHANGES 1024 | ||
83 | |||
84 | /* XRAM | ||
85 | * | ||
86 | * This is a 64KB register area. | ||
87 | * From the documentation, it seems like it is finally able to cope | ||
88 | * at least with 1,2,4 byte accesses for read and 2,4 byte accesses for write. | ||
89 | */ | ||
90 | |||
91 | /* Circular Queue */ | ||
92 | |||
93 | #define SOCAL_CQ_REQ_OFFSET 0x200 | ||
94 | #define SOCAL_CQ_RSP_OFFSET 0x220 | ||
95 | |||
96 | typedef struct { | ||
97 | u32 address; | ||
98 | u8 in; | ||
99 | u8 out; | ||
100 | u8 last; | ||
101 | u8 seqno; | ||
102 | } socal_hw_cq; | ||
103 | |||
104 | #define SOCAL_PORT_A 0x0000 /* From/To Port A */ | ||
105 | #define SOCAL_PORT_B 0x0001 /* From/To Port A */ | ||
106 | #define SOCAL_FC_HDR 0x0002 /* Contains FC Header */ | ||
107 | #define SOCAL_NORSP 0x0004 /* Don't generate response nor interrupt */ | ||
108 | #define SOCAL_NOINT 0x0008 /* Generate response but not interrupt */ | ||
109 | #define SOCAL_XFERRDY 0x0010 /* Generate XFERRDY */ | ||
110 | #define SOCAL_IGNOREPARAM 0x0020 /* Ignore PARAM field in the FC header */ | ||
111 | #define SOCAL_COMPLETE 0x0040 /* Command completed */ | ||
112 | #define SOCAL_UNSOLICITED 0x0080 /* For request this is the packet to establish unsolicited pools, */ | ||
113 | /* for rsp this is unsolicited packet */ | ||
114 | #define SOCAL_STATUS 0x0100 /* State change (on/off line) */ | ||
115 | #define SOCAL_RSP_HDR 0x0200 /* Return frame header in any case */ | ||
116 | |||
117 | typedef struct { | ||
118 | u32 token; | ||
119 | u16 flags; | ||
120 | u8 class; | ||
121 | u8 segcnt; | ||
122 | u32 bytecnt; | ||
123 | } socal_hdr; | ||
124 | |||
125 | typedef struct { | ||
126 | u32 base; | ||
127 | u32 count; | ||
128 | } socal_data; | ||
129 | |||
130 | #define SOCAL_CQTYPE_NOP 0x00 | ||
131 | #define SOCAL_CQTYPE_OUTBOUND 0x01 | ||
132 | #define SOCAL_CQTYPE_INBOUND 0x02 | ||
133 | #define SOCAL_CQTYPE_SIMPLE 0x03 | ||
134 | #define SOCAL_CQTYPE_IO_WRITE 0x04 | ||
135 | #define SOCAL_CQTYPE_IO_READ 0x05 | ||
136 | #define SOCAL_CQTYPE_UNSOLICITED 0x06 | ||
137 | #define SOCAL_CQTYPE_BYPASS_DEV 0x06 | ||
138 | #define SOCAL_CQTYPE_DIAG 0x07 | ||
139 | #define SOCAL_CQTYPE_OFFLINE 0x08 | ||
140 | #define SOCAL_CQTYPE_ADD_POOL 0x09 | ||
141 | #define SOCAL_CQTYPE_DELETE_POOL 0x0a | ||
142 | #define SOCAL_CQTYPE_ADD_BUFFER 0x0b | ||
143 | #define SOCAL_CQTYPE_ADD_POOL_BUFFER 0x0c | ||
144 | #define SOCAL_CQTYPE_REQUEST_ABORT 0x0d | ||
145 | #define SOCAL_CQTYPE_REQUEST_LIP 0x0e | ||
146 | #define SOCAL_CQTYPE_REPORT_MAP 0x0f | ||
147 | #define SOCAL_CQTYPE_RESPONSE 0x10 | ||
148 | #define SOCAL_CQTYPE_INLINE 0x20 | ||
149 | |||
150 | #define SOCAL_CQFLAGS_CONT 0x01 | ||
151 | #define SOCAL_CQFLAGS_FULL 0x02 | ||
152 | #define SOCAL_CQFLAGS_BADHDR 0x04 | ||
153 | #define SOCAL_CQFLAGS_BADPKT 0x08 | ||
154 | |||
155 | typedef struct { | ||
156 | socal_hdr shdr; | ||
157 | socal_data data[3]; | ||
158 | fc_hdr fchdr; | ||
159 | u8 count; | ||
160 | u8 type; | ||
161 | u8 flags; | ||
162 | u8 seqno; | ||
163 | } socal_req; | ||
164 | |||
165 | #define SOCAL_OK 0 | ||
166 | #define SOCAL_P_RJT 2 | ||
167 | #define SOCAL_F_RJT 3 | ||
168 | #define SOCAL_P_BSY 4 | ||
169 | #define SOCAL_F_BSY 5 | ||
170 | #define SOCAL_ONLINE 0x10 | ||
171 | #define SOCAL_OFFLINE 0x11 | ||
172 | #define SOCAL_TIMEOUT 0x12 | ||
173 | #define SOCAL_OVERRUN 0x13 | ||
174 | #define SOCAL_ONLINE_LOOP 0x14 | ||
175 | #define SOCAL_OLD_PORT 0x15 | ||
176 | #define SOCAL_AL_PORT 0x16 | ||
177 | #define SOCAL_UNKOWN_CQ_TYPE 0x20 | ||
178 | #define SOCAL_BAD_SEG_CNT 0x21 | ||
179 | #define SOCAL_MAX_XCHG_EXCEEDED 0x22 | ||
180 | #define SOCAL_BAD_XID 0x23 | ||
181 | #define SOCAL_XCHG_BUSY 0x24 | ||
182 | #define SOCAL_BAD_POOL_ID 0x25 | ||
183 | #define SOCAL_INSUFFICIENT_CQES 0x26 | ||
184 | #define SOCAL_ALLOC_FAIL 0x27 | ||
185 | #define SOCAL_BAD_SID 0x28 | ||
186 | #define SOCAL_NO_SEG_INIT 0x29 | ||
187 | #define SOCAL_BAD_DID 0x2a | ||
188 | #define SOCAL_ABORTED 0x30 | ||
189 | #define SOCAL_ABORT_FAILED 0x31 | ||
190 | |||
191 | typedef struct { | ||
192 | socal_hdr shdr; | ||
193 | u32 status; | ||
194 | socal_data data; | ||
195 | u8 xxx1[10]; | ||
196 | u16 ncmds; | ||
197 | fc_hdr fchdr; | ||
198 | u8 count; | ||
199 | u8 type; | ||
200 | u8 flags; | ||
201 | u8 seqno; | ||
202 | } socal_rsp; | ||
203 | |||
204 | typedef struct { | ||
205 | socal_hdr shdr; | ||
206 | u8 xxx1[48]; | ||
207 | u8 count; | ||
208 | u8 type; | ||
209 | u8 flags; | ||
210 | u8 seqno; | ||
211 | } socal_cmdonly; | ||
212 | |||
213 | #define SOCAL_DIAG_NOP 0x00 | ||
214 | #define SOCAL_DIAG_INT_LOOP 0x01 | ||
215 | #define SOCAL_DIAG_EXT_LOOP 0x02 | ||
216 | #define SOCAL_DIAG_REM_LOOP 0x03 | ||
217 | #define SOCAL_DIAG_XRAM_TEST 0x04 | ||
218 | #define SOCAL_DIAG_SOC_TEST 0x05 | ||
219 | #define SOCAL_DIAG_HCB_TEST 0x06 | ||
220 | #define SOCAL_DIAG_SOCLB_TEST 0x07 | ||
221 | #define SOCAL_DIAG_SRDSLB_TEST 0x08 | ||
222 | #define SOCAL_DIAG_EXTOE_TEST 0x09 | ||
223 | |||
224 | typedef struct { | ||
225 | socal_hdr shdr; | ||
226 | u32 cmd; | ||
227 | u8 xxx1[44]; | ||
228 | u8 count; | ||
229 | u8 type; | ||
230 | u8 flags; | ||
231 | u8 seqno; | ||
232 | } socal_diag_req; | ||
233 | |||
234 | #define SOCAL_POOL_MASK_RCTL 0x800000 | ||
235 | #define SOCAL_POOL_MASK_DID 0x700000 | ||
236 | #define SOCAL_POOL_MASK_SID 0x070000 | ||
237 | #define SOCAL_POOL_MASK_TYPE 0x008000 | ||
238 | #define SOCAL_POOL_MASK_F_CTL 0x007000 | ||
239 | #define SOCAL_POOL_MASK_SEQ_ID 0x000800 | ||
240 | #define SOCAL_POOL_MASK_D_CTL 0x000400 | ||
241 | #define SOCAL_POOL_MASK_SEQ_CNT 0x000300 | ||
242 | #define SOCAL_POOL_MASK_OX_ID 0x0000f0 | ||
243 | #define SOCAL_POOL_MASK_PARAM 0x00000f | ||
244 | |||
245 | typedef struct { | ||
246 | socal_hdr shdr; | ||
247 | u32 pool_id; | ||
248 | u32 header_mask; | ||
249 | u32 buf_size; | ||
250 | u32 entries; | ||
251 | u8 xxx1[8]; | ||
252 | fc_hdr fchdr; | ||
253 | u8 count; | ||
254 | u8 type; | ||
255 | u8 flags; | ||
256 | u8 seqno; | ||
257 | } socal_pool_req; | ||
258 | |||
259 | /* }}} */ | ||
260 | |||
261 | /* Now our software structures and constants we use to drive the beast {{{ */ | ||
262 | |||
263 | #define SOCAL_CQ_REQ0_SIZE 4 | ||
264 | #define SOCAL_CQ_REQ1_SIZE 256 | ||
265 | #define SOCAL_CQ_RSP0_SIZE 8 | ||
266 | #define SOCAL_CQ_RSP1_SIZE 4 | ||
267 | #define SOCAL_CQ_RSP2_SIZE 4 | ||
268 | |||
269 | #define SOCAL_SOLICITED_RSP_Q 0 | ||
270 | #define SOCAL_SOLICITED_BAD_RSP_Q 1 | ||
271 | #define SOCAL_UNSOLICITED_RSP_Q 2 | ||
272 | |||
273 | struct socal; | ||
274 | |||
275 | typedef struct { | ||
276 | /* This must come first */ | ||
277 | fc_channel fc; | ||
278 | struct socal *s; | ||
279 | u16 flags; | ||
280 | u16 mask; | ||
281 | } socal_port; | ||
282 | |||
283 | typedef struct { | ||
284 | socal_hw_cq __iomem *hw_cq; /* Related XRAM cq */ | ||
285 | socal_req *pool; | ||
286 | u8 in; | ||
287 | u8 out; | ||
288 | u8 last; | ||
289 | u8 seqno; | ||
290 | } socal_cq; | ||
291 | |||
292 | struct socal { | ||
293 | spinlock_t lock; | ||
294 | socal_port port[2]; /* Every SOCAL has one or two FC ports */ | ||
295 | socal_cq req[4]; /* Request CQs */ | ||
296 | socal_cq rsp[4]; /* Response CQs */ | ||
297 | int socal_no; | ||
298 | void __iomem *regs; | ||
299 | void __iomem *xram; | ||
300 | void __iomem *eeprom; | ||
301 | fc_wwn wwn; | ||
302 | u32 imask; /* Our copy of regs->imask */ | ||
303 | u32 cfg; /* Our copy of regs->cfg */ | ||
304 | char serv_params[80]; | ||
305 | struct socal *next; | ||
306 | int curr_port; /* Which port will have priority to fcp_queue_empty */ | ||
307 | |||
308 | socal_req * req_cpu; | ||
309 | u32 req_dvma; | ||
310 | }; | ||
311 | |||
312 | /* }}} */ | ||
313 | |||
314 | #endif /* !(__SOCAL_H) */ | ||