Commit 1ecd3902c6e16c2445165b872c49e73770b72da7
Committed by
James Bottomley
1 parent
d85714d81c
Exists in
master
and in
4 other branches
[SCSI] fc4: remove this and all associated drivers
This code has been slowly rotting for about eight years. It's currently impeding a few SCSI cleanups, and nobody seems to have hardware to test it any more. I talked to Dave Miller about it, and he agrees we can delete it. If anyone wants a software FC stack in future, they can retrieve this driver from git. Signed-off-by: Matthew Wilcox <matthew@wil.cx> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Showing 19 changed files with 0 additions and 4809 deletions Side-by-side Diff
- arch/sparc64/Kconfig
- drivers/Makefile
- drivers/fc4/Kconfig
- drivers/fc4/Makefile
- drivers/fc4/fc-al.h
- drivers/fc4/fc.c
- drivers/fc4/fc.h
- drivers/fc4/fc_syms.c
- drivers/fc4/fcp.h
- drivers/fc4/fcp_impl.h
- drivers/fc4/soc.c
- drivers/fc4/soc.h
- drivers/fc4/socal.c
- drivers/fc4/socal.h
- drivers/scsi/Makefile
- drivers/scsi/fcal.c
- drivers/scsi/fcal.h
- drivers/scsi/pluto.c
- drivers/scsi/pluto.h
arch/sparc64/Kconfig
drivers/Makefile
drivers/fc4/Kconfig
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 |
drivers/fc4/Makefile
drivers/fc4/fc-al.h
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) */ |
drivers/fc4/fc.c
Changes suppressed. Click to show
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"); |
drivers/fc4/fc.h
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) */ |
drivers/fc4/fc_syms.c
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 */ |
drivers/fc4/fcp.h
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) */ |
drivers/fc4/fcp_impl.h
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) */ |
drivers/fc4/soc.c
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"); |
drivers/fc4/soc.h
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) */ |
drivers/fc4/socal.c
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"); |
drivers/fc4/socal.h
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) */ |
drivers/scsi/Makefile
... | ... | @@ -115,7 +115,6 @@ |
115 | 115 | obj-$(CONFIG_BLK_DEV_IDESCSI) += ide-scsi.o |
116 | 116 | obj-$(CONFIG_SCSI_MESH) += mesh.o |
117 | 117 | obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o |
118 | -obj-$(CONFIG_SCSI_PLUTO) += pluto.o | |
119 | 118 | obj-$(CONFIG_SCSI_DECNCR) += NCR53C9x.o dec_esp.o |
120 | 119 | obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o |
121 | 120 | obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o |
... | ... | @@ -123,7 +122,6 @@ |
123 | 122 | obj-$(CONFIG_SCSI_IMM) += imm.o |
124 | 123 | obj-$(CONFIG_JAZZ_ESP) += esp_scsi.o jazz_esp.o |
125 | 124 | obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o |
126 | -obj-$(CONFIG_SCSI_FCAL) += fcal.o | |
127 | 125 | obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o |
128 | 126 | obj-$(CONFIG_SCSI_SNI_53C710) += 53c700.o sni_53c710.o |
129 | 127 | obj-$(CONFIG_SCSI_NSP32) += nsp32.o |
drivers/scsi/fcal.c
1 | -/* fcal.c: Fibre Channel Arbitrated Loop SCSI host adapter driver. | |
2 | - * | |
3 | - * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz) | |
4 | - * | |
5 | - */ | |
6 | - | |
7 | -#include <linux/kernel.h> | |
8 | -#include <linux/delay.h> | |
9 | -#include <linux/types.h> | |
10 | -#include <linux/string.h> | |
11 | -#include <linux/slab.h> | |
12 | -#include <linux/blkdev.h> | |
13 | -#include <linux/proc_fs.h> | |
14 | -#include <linux/stat.h> | |
15 | -#include <linux/init.h> | |
16 | -#ifdef CONFIG_KMOD | |
17 | -#include <linux/kmod.h> | |
18 | -#endif | |
19 | - | |
20 | -#include <asm/irq.h> | |
21 | - | |
22 | -#include "scsi.h" | |
23 | -#include <scsi/scsi_host.h> | |
24 | -#include "../fc4/fcp_impl.h" | |
25 | -#include "fcal.h" | |
26 | - | |
27 | -#include <linux/module.h> | |
28 | - | |
29 | -/* #define FCAL_DEBUG */ | |
30 | - | |
31 | -#define fcal_printk printk ("FCAL %s: ", fc->name); printk | |
32 | - | |
33 | -#ifdef FCAL_DEBUG | |
34 | -#define FCALD(x) fcal_printk x; | |
35 | -#define FCALND(x) printk ("FCAL: "); printk x; | |
36 | -#else | |
37 | -#define FCALD(x) | |
38 | -#define FCALND(x) | |
39 | -#endif | |
40 | - | |
41 | -static unsigned char alpa2target[] = { | |
42 | -0x7e, 0x7d, 0x7c, 0xff, 0x7b, 0xff, 0xff, 0xff, 0x7a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, | |
43 | -0x78, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x76, 0xff, 0xff, 0x75, 0xff, 0x74, 0x73, 0x72, | |
44 | -0xff, 0xff, 0xff, 0x71, 0xff, 0x70, 0x6f, 0x6e, 0xff, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0xff, | |
45 | -0xff, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0xff, 0xff, 0x61, 0x60, 0xff, 0x5f, 0xff, 0xff, 0xff, | |
46 | -0xff, 0xff, 0xff, 0x5e, 0xff, 0x5d, 0x5c, 0x5b, 0xff, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0xff, | |
47 | -0xff, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0xff, 0xff, 0x4e, 0x4d, 0xff, 0x4c, 0xff, 0xff, 0xff, | |
48 | -0xff, 0xff, 0xff, 0x4b, 0xff, 0x4a, 0x49, 0x48, 0xff, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0xff, | |
49 | -0xff, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0xff, 0xff, 0x3b, 0x3a, 0xff, 0x39, 0xff, 0xff, 0xff, | |
50 | -0x38, 0x37, 0x36, 0xff, 0x35, 0xff, 0xff, 0xff, 0x34, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x33, | |
51 | -0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x30, 0xff, 0xff, 0x2f, 0xff, 0x2e, 0x2d, 0x2c, | |
52 | -0xff, 0xff, 0xff, 0x2b, 0xff, 0x2a, 0x29, 0x28, 0xff, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0xff, | |
53 | -0xff, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0xff, 0xff, 0x1b, 0x1a, 0xff, 0x19, 0xff, 0xff, 0xff, | |
54 | -0xff, 0xff, 0xff, 0x18, 0xff, 0x17, 0x16, 0x15, 0xff, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0xff, | |
55 | -0xff, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0xff, 0xff, 0x08, 0x07, 0xff, 0x06, 0xff, 0xff, 0xff, | |
56 | -0x05, 0x04, 0x03, 0xff, 0x02, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 | |
57 | -}; | |
58 | - | |
59 | -static unsigned char target2alpa[] = { | |
60 | -0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, | |
61 | -0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5, 0xb4, 0xb3, | |
62 | -0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, | |
63 | -0x98, 0x97, 0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79, 0x76, 0x75, 0x74, 0x73, | |
64 | -0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56, | |
65 | -0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, | |
66 | -0x3a, 0x39, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x27, 0x26, | |
67 | -0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17, 0x10, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x00 | |
68 | -}; | |
69 | - | |
70 | -static int fcal_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd); | |
71 | - | |
72 | -int fcal_slave_configure(struct scsi_device *device) | |
73 | -{ | |
74 | - int depth_to_use; | |
75 | - | |
76 | - if (device->tagged_supported) | |
77 | - depth_to_use = /* 254 */ 8; | |
78 | - else | |
79 | - depth_to_use = 2; | |
80 | - | |
81 | - scsi_adjust_queue_depth(device, | |
82 | - (device->tagged_supported ? | |
83 | - MSG_SIMPLE_TAG : 0), | |
84 | - depth_to_use); | |
85 | - | |
86 | - return 0; | |
87 | -} | |
88 | - | |
89 | -/* Detect all FC Arbitrated Loops attached to the machine. | |
90 | - fc4 module has done all the work for us... */ | |
91 | -int __init fcal_detect(struct scsi_host_template *tpnt) | |
92 | -{ | |
93 | - int nfcals = 0; | |
94 | - fc_channel *fc; | |
95 | - int fcalcount; | |
96 | - int i; | |
97 | - | |
98 | - tpnt->proc_name = "fcal"; | |
99 | - fcalcount = 0; | |
100 | - for_each_online_fc_channel(fc) | |
101 | - if (fc->posmap) | |
102 | - fcalcount++; | |
103 | - FCALND(("%d channels online\n", fcalcount)) | |
104 | - if (!fcalcount) { | |
105 | -#if defined(MODULE) && defined(CONFIG_FC4_SOCAL_MODULE) && defined(CONFIG_KMOD) | |
106 | - request_module("socal"); | |
107 | - | |
108 | - for_each_online_fc_channel(fc) | |
109 | - if (fc->posmap) | |
110 | - fcalcount++; | |
111 | - if (!fcalcount) | |
112 | -#endif | |
113 | - return 0; | |
114 | - } | |
115 | - for_each_online_fc_channel(fc) { | |
116 | - struct Scsi_Host *host; | |
117 | - long *ages; | |
118 | - struct fcal *fcal; | |
119 | - | |
120 | - if (!fc->posmap) continue; | |
121 | - | |
122 | - /* Strange, this is already registered to some other SCSI host, then it cannot be fcal */ | |
123 | - if (fc->scsi_name[0]) continue; | |
124 | - memcpy (fc->scsi_name, "FCAL", 4); | |
125 | - | |
126 | - fc->can_queue = FCAL_CAN_QUEUE; | |
127 | - fc->rsp_size = 64; | |
128 | - fc->encode_addr = fcal_encode_addr; | |
129 | - | |
130 | - ages = kmalloc (128 * sizeof(long), GFP_KERNEL); | |
131 | - if (!ages) continue; | |
132 | - | |
133 | - host = scsi_register (tpnt, sizeof (struct fcal)); | |
134 | - if (!host) | |
135 | - { | |
136 | - kfree(ages); | |
137 | - continue; | |
138 | - } | |
139 | - | |
140 | - if (!try_module_get(fc->module)) { | |
141 | - kfree(ages); | |
142 | - scsi_unregister(host); | |
143 | - continue; | |
144 | - } | |
145 | - | |
146 | - nfcals++; | |
147 | - | |
148 | - fcal = (struct fcal *)host->hostdata; | |
149 | - | |
150 | - fc->fcp_register(fc, TYPE_SCSI_FCP, 0); | |
151 | - | |
152 | - for (i = 0; i < fc->posmap->len; i++) { | |
153 | - int status, target, alpa; | |
154 | - | |
155 | - alpa = fc->posmap->list[i]; | |
156 | - FCALD(("Sending PLOGI to %02x\n", alpa)) | |
157 | - target = alpa2target[alpa]; | |
158 | - status = fc_do_plogi(fc, alpa, fcal->node_wwn + target, | |
159 | - fcal->nport_wwn + target); | |
160 | - FCALD(("PLOGI returned with status %d\n", status)) | |
161 | - if (status != FC_STATUS_OK) | |
162 | - continue; | |
163 | - FCALD(("Sending PRLI to %02x\n", alpa)) | |
164 | - status = fc_do_prli(fc, alpa); | |
165 | - FCALD(("PRLI returned with status %d\n", status)) | |
166 | - if (status == FC_STATUS_OK) | |
167 | - fcal->map[target] = 1; | |
168 | - } | |
169 | - | |
170 | - host->max_id = 127; | |
171 | - host->irq = fc->irq; | |
172 | -#ifdef __sparc_v9__ | |
173 | - host->unchecked_isa_dma = 1; | |
174 | -#endif | |
175 | - | |
176 | - fc->channels = 1; | |
177 | - fc->targets = 127; | |
178 | - fc->ages = ages; | |
179 | - memset (ages, 0, 128 * sizeof(long)); | |
180 | - | |
181 | - fcal->fc = fc; | |
182 | - | |
183 | - FCALD(("Found FCAL\n")) | |
184 | - } | |
185 | - if (nfcals) | |
186 | -#ifdef __sparc__ | |
187 | - printk ("FCAL: Total of %d Sun Enterprise Network Array (A5000 or EX500) channels found\n", nfcals); | |
188 | -#else | |
189 | - printk ("FCAL: Total of %d Fibre Channel Arbitrated Loops found\n", nfcals); | |
190 | -#endif | |
191 | - return nfcals; | |
192 | -} | |
193 | - | |
194 | -int fcal_release(struct Scsi_Host *host) | |
195 | -{ | |
196 | - struct fcal *fcal = (struct fcal *)host->hostdata; | |
197 | - fc_channel *fc = fcal->fc; | |
198 | - | |
199 | - module_put(fc->module); | |
200 | - | |
201 | - fc->fcp_register(fc, TYPE_SCSI_FCP, 1); | |
202 | - FCALND((" releasing fcal.\n")); | |
203 | - kfree (fc->ages); | |
204 | - FCALND(("released fcal!\n")); | |
205 | - return 0; | |
206 | -} | |
207 | - | |
208 | -#undef SPRINTF | |
209 | -#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } | |
210 | - | |
211 | -int fcal_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout) | |
212 | -{ | |
213 | - struct fcal *fcal; | |
214 | - fc_channel *fc; | |
215 | - char *pos = buffer; | |
216 | - int i, j; | |
217 | - | |
218 | - if (inout) return length; | |
219 | - | |
220 | - fcal = (struct fcal *)host->hostdata; | |
221 | - fc = fcal->fc; | |
222 | - | |
223 | -#ifdef __sparc__ | |
224 | - SPRINTF ("Sun Enterprise Network Array (A5000 or E?500) on %s PROM node %x\n", fc->name, fc->dev->prom_node); | |
225 | -#else | |
226 | - SPRINTF ("Fibre Channel Arbitrated Loop on %s\n", fc->name); | |
227 | -#endif | |
228 | - SPRINTF ("Initiator AL-PA: %02x\n", fc->sid); | |
229 | - | |
230 | - SPRINTF ("\nAttached devices:\n"); | |
231 | - | |
232 | - for (i = 0; i < fc->posmap->len; i++) { | |
233 | - unsigned char alpa = fc->posmap->list[i]; | |
234 | - unsigned char target; | |
235 | - u32 *u1, *u2; | |
236 | - | |
237 | - target = alpa2target[alpa]; | |
238 | - u1 = (u32 *)&fcal->nport_wwn[target]; | |
239 | - u2 = (u32 *)&fcal->node_wwn[target]; | |
240 | - if (!u1[0] && !u1[1]) { | |
241 | - SPRINTF (" [AL-PA: %02x] Not responded to PLOGI\n", alpa); | |
242 | - } else if (!fcal->map[target]) { | |
243 | - SPRINTF (" [AL-PA: %02x, Port WWN: %08x%08x, Node WWN: %08x%08x] Not responded to PRLI\n", | |
244 | - alpa, u1[0], u1[1], u2[0], u2[1]); | |
245 | - } else { | |
246 | - struct scsi_device *scd; | |
247 | - shost_for_each_device(scd, host) | |
248 | - if (scd->id == target) { | |
249 | - SPRINTF (" [AL-PA: %02x, Id: %02d, Port WWN: %08x%08x, Node WWN: %08x%08x] ", | |
250 | - alpa, target, u1[0], u1[1], u2[0], u2[1]); | |
251 | - SPRINTF ("%s ", scsi_device_type(scd->type)); | |
252 | - | |
253 | - for (j = 0; (j < 8) && (scd->vendor[j] >= 0x20); j++) | |
254 | - SPRINTF ("%c", scd->vendor[j]); | |
255 | - SPRINTF (" "); | |
256 | - | |
257 | - for (j = 0; (j < 16) && (scd->model[j] >= 0x20); j++) | |
258 | - SPRINTF ("%c", scd->model[j]); | |
259 | - | |
260 | - SPRINTF ("\n"); | |
261 | - } | |
262 | - } | |
263 | - } | |
264 | - SPRINTF ("\n"); | |
265 | - | |
266 | - *start = buffer + offset; | |
267 | - | |
268 | - if ((pos - buffer) < offset) | |
269 | - return 0; | |
270 | - else if (pos - buffer - offset < length) | |
271 | - return pos - buffer - offset; | |
272 | - else | |
273 | - return length; | |
274 | -} | |
275 | - | |
276 | -/* | |
277 | - For FC-AL, we use a simple addressing: we have just one channel 0, | |
278 | - and all AL-PAs are mapped to targets 0..0x7e | |
279 | - */ | |
280 | -static int fcal_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd) | |
281 | -{ | |
282 | - struct fcal *f; | |
283 | - | |
284 | - /* We don't support LUNs yet - I'm not sure if LUN should be in SCSI fcp_cdb, or in second byte of addr[0] */ | |
285 | - if (SCpnt->cmnd[1] & 0xe0) return -EINVAL; | |
286 | - /* FC-PLDA tells us... */ | |
287 | - memset(addr, 0, 8); | |
288 | - f = (struct fcal *)SCpnt->device->host->hostdata; | |
289 | - if (!f->map[SCpnt->device->id]) | |
290 | - return -EINVAL; | |
291 | - /* Now, determine DID: It will be Native Identifier, so we zero upper | |
292 | - 2 bytes of the 3 byte DID, lowest byte will be AL-PA */ | |
293 | - fcmd->did = target2alpa[SCpnt->device->id]; | |
294 | - FCALD(("trying DID %06x\n", fcmd->did)) | |
295 | - return 0; | |
296 | -} | |
297 | - | |
298 | -static struct scsi_host_template driver_template = { | |
299 | - .name = "Fibre Channel Arbitrated Loop", | |
300 | - .detect = fcal_detect, | |
301 | - .release = fcal_release, | |
302 | - .proc_info = fcal_proc_info, | |
303 | - .queuecommand = fcp_scsi_queuecommand, | |
304 | - .slave_configure = fcal_slave_configure, | |
305 | - .can_queue = FCAL_CAN_QUEUE, | |
306 | - .this_id = -1, | |
307 | - .sg_tablesize = 1, | |
308 | - .cmd_per_lun = 1, | |
309 | - .use_clustering = ENABLE_CLUSTERING, | |
310 | - .eh_abort_handler = fcp_scsi_abort, | |
311 | - .eh_device_reset_handler = fcp_scsi_dev_reset, | |
312 | - .eh_host_reset_handler = fcp_scsi_host_reset, | |
313 | -}; | |
314 | -#include "scsi_module.c" | |
315 | - | |
316 | -MODULE_LICENSE("GPL"); |
drivers/scsi/fcal.h
1 | -/* fcal.h: Generic Fibre Channel Arbitrated Loop SCSI host adapter driver definitions. | |
2 | - * | |
3 | - * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz) | |
4 | - */ | |
5 | - | |
6 | -#ifndef _FCAL_H | |
7 | -#define _FCAL_H | |
8 | - | |
9 | -#include "../fc4/fcp_impl.h" | |
10 | - | |
11 | -struct fcal { | |
12 | - /* fc must be first */ | |
13 | - fc_channel *fc; | |
14 | - unsigned char map[128]; | |
15 | - fc_wwn nport_wwn[128]; | |
16 | - fc_wwn node_wwn[128]; | |
17 | -}; | |
18 | - | |
19 | -/* Arbitrary constant. Cannot be too large, as fc4 layer has limitations | |
20 | - for a particular channel */ | |
21 | -#define FCAL_CAN_QUEUE 512 | |
22 | - | |
23 | -int fcal_detect(struct scsi_host_template *); | |
24 | -int fcal_release(struct Scsi_Host *); | |
25 | -int fcal_slave_configure(struct scsi_device *); | |
26 | - | |
27 | -#endif /* !(_FCAL_H) */ |
drivers/scsi/pluto.c
1 | -/* pluto.c: SparcSTORAGE Array SCSI host adapter driver. | |
2 | - * | |
3 | - * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | |
4 | - * | |
5 | - */ | |
6 | - | |
7 | -#include <linux/completion.h> | |
8 | -#include <linux/kernel.h> | |
9 | -#include <linux/delay.h> | |
10 | -#include <linux/types.h> | |
11 | -#include <linux/string.h> | |
12 | -#include <linux/slab.h> | |
13 | -#include <linux/blkdev.h> | |
14 | -#include <linux/proc_fs.h> | |
15 | -#include <linux/stat.h> | |
16 | -#include <linux/init.h> | |
17 | -#ifdef CONFIG_KMOD | |
18 | -#include <linux/kmod.h> | |
19 | -#endif | |
20 | - | |
21 | -#include <asm/irq.h> | |
22 | - | |
23 | -#include "scsi.h" | |
24 | -#include <scsi/scsi_host.h> | |
25 | -#include "../fc4/fcp_impl.h" | |
26 | -#include "pluto.h" | |
27 | - | |
28 | -#include <linux/module.h> | |
29 | - | |
30 | -#define RQ_SCSI_BUSY 0xffff | |
31 | -#define RQ_SCSI_DONE 0xfffe | |
32 | - | |
33 | -/* #define PLUTO_DEBUG */ | |
34 | - | |
35 | -#define pluto_printk printk ("PLUTO %s: ", fc->name); printk | |
36 | - | |
37 | -#ifdef PLUTO_DEBUG | |
38 | -#define PLD(x) pluto_printk x; | |
39 | -#define PLND(x) printk ("PLUTO: "); printk x; | |
40 | -#else | |
41 | -#define PLD(x) | |
42 | -#define PLND(x) | |
43 | -#endif | |
44 | - | |
45 | -static struct ctrl_inquiry { | |
46 | - struct Scsi_Host host; | |
47 | - struct pluto pluto; | |
48 | - Scsi_Cmnd cmd; | |
49 | - char inquiry[256]; | |
50 | - fc_channel *fc; | |
51 | -} *fcs __initdata; | |
52 | -static int fcscount __initdata = 0; | |
53 | -static atomic_t fcss __initdata = ATOMIC_INIT(0); | |
54 | -static DECLARE_COMPLETION(fc_detect_complete); | |
55 | - | |
56 | -static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd); | |
57 | - | |
58 | -static void __init pluto_detect_done(Scsi_Cmnd *SCpnt) | |
59 | -{ | |
60 | - /* Do nothing */ | |
61 | -} | |
62 | - | |
63 | -static void __init pluto_detect_scsi_done(Scsi_Cmnd *SCpnt) | |
64 | -{ | |
65 | - PLND(("Detect done %08lx\n", (long)SCpnt)) | |
66 | - if (atomic_dec_and_test (&fcss)) | |
67 | - complete(&fc_detect_complete); | |
68 | -} | |
69 | - | |
70 | -int pluto_slave_configure(struct scsi_device *device) | |
71 | -{ | |
72 | - int depth_to_use; | |
73 | - | |
74 | - if (device->tagged_supported) | |
75 | - depth_to_use = /* 254 */ 8; | |
76 | - else | |
77 | - depth_to_use = 2; | |
78 | - | |
79 | - scsi_adjust_queue_depth(device, | |
80 | - (device->tagged_supported ? | |
81 | - MSG_SIMPLE_TAG : 0), | |
82 | - depth_to_use); | |
83 | - | |
84 | - return 0; | |
85 | -} | |
86 | - | |
87 | -/* Detect all SSAs attached to the machine. | |
88 | - To be fast, do it on all online FC channels at the same time. */ | |
89 | -int __init pluto_detect(struct scsi_host_template *tpnt) | |
90 | -{ | |
91 | - int i, retry, nplutos; | |
92 | - fc_channel *fc; | |
93 | - struct scsi_device dev; | |
94 | - | |
95 | - tpnt->proc_name = "pluto"; | |
96 | - fcscount = 0; | |
97 | - for_each_online_fc_channel(fc) { | |
98 | - if (!fc->posmap) | |
99 | - fcscount++; | |
100 | - } | |
101 | - PLND(("%d channels online\n", fcscount)) | |
102 | - if (!fcscount) { | |
103 | -#if defined(MODULE) && defined(CONFIG_FC4_SOC_MODULE) && defined(CONFIG_KMOD) | |
104 | - request_module("soc"); | |
105 | - | |
106 | - for_each_online_fc_channel(fc) { | |
107 | - if (!fc->posmap) | |
108 | - fcscount++; | |
109 | - } | |
110 | - if (!fcscount) | |
111 | -#endif | |
112 | - return 0; | |
113 | - } | |
114 | - fcs = kcalloc(fcscount, sizeof (struct ctrl_inquiry), GFP_DMA); | |
115 | - if (!fcs) { | |
116 | - printk ("PLUTO: Not enough memory to probe\n"); | |
117 | - return 0; | |
118 | - } | |
119 | - | |
120 | - memset (&dev, 0, sizeof(dev)); | |
121 | - atomic_set (&fcss, fcscount); | |
122 | - | |
123 | - i = 0; | |
124 | - for_each_online_fc_channel(fc) { | |
125 | - Scsi_Cmnd *SCpnt; | |
126 | - struct Scsi_Host *host; | |
127 | - struct pluto *pluto; | |
128 | - | |
129 | - if (i == fcscount) break; | |
130 | - if (fc->posmap) continue; | |
131 | - | |
132 | - PLD(("trying to find SSA\n")) | |
133 | - | |
134 | - /* If this is already registered to some other SCSI host, then it cannot be pluto */ | |
135 | - if (fc->scsi_name[0]) continue; | |
136 | - memcpy (fc->scsi_name, "SSA", 4); | |
137 | - | |
138 | - fcs[i].fc = fc; | |
139 | - | |
140 | - fc->can_queue = PLUTO_CAN_QUEUE; | |
141 | - fc->rsp_size = 64; | |
142 | - fc->encode_addr = pluto_encode_addr; | |
143 | - | |
144 | - fc->fcp_register(fc, TYPE_SCSI_FCP, 0); | |
145 | - | |
146 | - SCpnt = &(fcs[i].cmd); | |
147 | - host = &(fcs[i].host); | |
148 | - pluto = (struct pluto *)host->hostdata; | |
149 | - | |
150 | - pluto->fc = fc; | |
151 | - | |
152 | - SCpnt->cmnd[0] = INQUIRY; | |
153 | - SCpnt->cmnd[4] = 255; | |
154 | - | |
155 | - /* FC layer requires this, so that SCpnt->device->tagged_supported is initially 0 */ | |
156 | - SCpnt->device = &dev; | |
157 | - dev.host = host; | |
158 | - | |
159 | - SCpnt->cmd_len = COMMAND_SIZE(INQUIRY); | |
160 | - | |
161 | - SCpnt->request->cmd_flags &= ~REQ_STARTED; | |
162 | - | |
163 | - SCpnt->request_bufflen = 256; | |
164 | - SCpnt->request_buffer = fcs[i].inquiry; | |
165 | - PLD(("set up %d %08lx\n", i, (long)SCpnt)) | |
166 | - i++; | |
167 | - } | |
168 | - | |
169 | - for (retry = 0; retry < 5; retry++) { | |
170 | - for (i = 0; i < fcscount; i++) { | |
171 | - if (!fcs[i].fc) break; | |
172 | - if (!(fcs[i].cmd.request->cmd_flags & REQ_STARTED)) { | |
173 | - fcs[i].cmd.request->cmd_flags |= REQ_STARTED; | |
174 | - disable_irq(fcs[i].fc->irq); | |
175 | - PLND(("queuecommand %d %d\n", retry, i)) | |
176 | - fcp_scsi_queuecommand (&(fcs[i].cmd), | |
177 | - pluto_detect_scsi_done); | |
178 | - enable_irq(fcs[i].fc->irq); | |
179 | - } | |
180 | - } | |
181 | - | |
182 | - wait_for_completion_timeout(&fc_detect_complete, 10 * HZ); | |
183 | - PLND(("Woken up\n")) | |
184 | - if (!atomic_read(&fcss)) | |
185 | - break; /* All fc channels have answered us */ | |
186 | - } | |
187 | - | |
188 | - PLND(("Finished search\n")) | |
189 | - for (i = 0, nplutos = 0; i < fcscount; i++) { | |
190 | - Scsi_Cmnd *SCpnt; | |
191 | - | |
192 | - if (!(fc = fcs[i].fc)) break; | |
193 | - | |
194 | - SCpnt = &(fcs[i].cmd); | |
195 | - | |
196 | - /* Let FC mid-level free allocated resources */ | |
197 | - pluto_detect_scsi_done(SCpnt); | |
198 | - | |
199 | - if (!SCpnt->result) { | |
200 | - struct pluto_inquiry *inq; | |
201 | - struct pluto *pluto; | |
202 | - struct Scsi_Host *host; | |
203 | - | |
204 | - inq = (struct pluto_inquiry *)fcs[i].inquiry; | |
205 | - | |
206 | - if ((inq->dtype & 0x1f) == TYPE_PROCESSOR && | |
207 | - !strncmp (inq->vendor_id, "SUN", 3) && | |
208 | - !strncmp (inq->product_id, "SSA", 3)) { | |
209 | - char *p; | |
210 | - long *ages; | |
211 | - | |
212 | - ages = kcalloc((inq->channels + 1) * inq->targets, sizeof(long), GFP_KERNEL); | |
213 | - if (!ages) continue; | |
214 | - | |
215 | - host = scsi_register (tpnt, sizeof (struct pluto)); | |
216 | - if(!host) | |
217 | - { | |
218 | - kfree(ages); | |
219 | - continue; | |
220 | - } | |
221 | - | |
222 | - if (!try_module_get(fc->module)) { | |
223 | - kfree(ages); | |
224 | - scsi_unregister(host); | |
225 | - continue; | |
226 | - } | |
227 | - | |
228 | - nplutos++; | |
229 | - | |
230 | - pluto = (struct pluto *)host->hostdata; | |
231 | - | |
232 | - host->max_id = inq->targets; | |
233 | - host->max_channel = inq->channels; | |
234 | - host->irq = fc->irq; | |
235 | - | |
236 | - fc->channels = inq->channels + 1; | |
237 | - fc->targets = inq->targets; | |
238 | - fc->ages = ages; | |
239 | - | |
240 | - pluto->fc = fc; | |
241 | - memcpy (pluto->rev_str, inq->revision, 4); | |
242 | - pluto->rev_str[4] = 0; | |
243 | - p = strchr (pluto->rev_str, ' '); | |
244 | - if (p) *p = 0; | |
245 | - memcpy (pluto->fw_rev_str, inq->fw_revision, 4); | |
246 | - pluto->fw_rev_str[4] = 0; | |
247 | - p = strchr (pluto->fw_rev_str, ' '); | |
248 | - if (p) *p = 0; | |
249 | - memcpy (pluto->serial_str, inq->serial, 12); | |
250 | - pluto->serial_str[12] = 0; | |
251 | - p = strchr (pluto->serial_str, ' '); | |
252 | - if (p) *p = 0; | |
253 | - | |
254 | - PLD(("Found SSA rev %s fw rev %s serial %s %dx%d\n", pluto->rev_str, pluto->fw_rev_str, pluto->serial_str, host->max_channel, host->max_id)) | |
255 | - } else | |
256 | - fc->fcp_register(fc, TYPE_SCSI_FCP, 1); | |
257 | - } else | |
258 | - fc->fcp_register(fc, TYPE_SCSI_FCP, 1); | |
259 | - } | |
260 | - kfree(fcs); | |
261 | - if (nplutos) | |
262 | - printk ("PLUTO: Total of %d SparcSTORAGE Arrays found\n", nplutos); | |
263 | - return nplutos; | |
264 | -} | |
265 | - | |
266 | -int pluto_release(struct Scsi_Host *host) | |
267 | -{ | |
268 | - struct pluto *pluto = (struct pluto *)host->hostdata; | |
269 | - fc_channel *fc = pluto->fc; | |
270 | - | |
271 | - module_put(fc->module); | |
272 | - | |
273 | - fc->fcp_register(fc, TYPE_SCSI_FCP, 1); | |
274 | - PLND((" releasing pluto.\n")); | |
275 | - kfree (fc->ages); | |
276 | - PLND(("released pluto!\n")); | |
277 | - return 0; | |
278 | -} | |
279 | - | |
280 | -const char *pluto_info(struct Scsi_Host *host) | |
281 | -{ | |
282 | - static char buf[128], *p; | |
283 | - struct pluto *pluto = (struct pluto *) host->hostdata; | |
284 | - | |
285 | - sprintf(buf, "SUN SparcSTORAGE Array %s fw %s serial %s %dx%d on %s", | |
286 | - pluto->rev_str, pluto->fw_rev_str, pluto->serial_str, | |
287 | - host->max_channel, host->max_id, pluto->fc->name); | |
288 | -#ifdef __sparc__ | |
289 | - p = strchr(buf, 0); | |
290 | - sprintf(p, " PROM node %x", pluto->fc->dev->prom_node); | |
291 | -#endif | |
292 | - return buf; | |
293 | -} | |
294 | - | |
295 | -/* SSA uses this FC4S addressing: | |
296 | - switch (addr[0]) | |
297 | - { | |
298 | - case 0: CONTROLLER - All of addr[1]..addr[3] has to be 0 | |
299 | - case 1: SINGLE DISK - addr[1] channel, addr[2] id, addr[3] 0 | |
300 | - case 2: DISK GROUP - ??? | |
301 | - } | |
302 | - | |
303 | - So that SCSI mid-layer can access to these, we reserve | |
304 | - channel 0 id 0 lun 0 for CONTROLLER | |
305 | - and channels 1 .. max_channel are normal single disks. | |
306 | - */ | |
307 | -static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd) | |
308 | -{ | |
309 | - PLND(("encode addr %d %d %d\n", SCpnt->device->channel, SCpnt->device->id, SCpnt->cmnd[1] & 0xe0)) | |
310 | - /* We don't support LUNs - neither does SSA :) */ | |
311 | - if (SCpnt->cmnd[1] & 0xe0) | |
312 | - return -EINVAL; | |
313 | - if (!SCpnt->device->channel) { | |
314 | - if (SCpnt->device->id) | |
315 | - return -EINVAL; | |
316 | - memset (addr, 0, 4 * sizeof(u16)); | |
317 | - } else { | |
318 | - addr[0] = 1; | |
319 | - addr[1] = SCpnt->device->channel - 1; | |
320 | - addr[2] = SCpnt->device->id; | |
321 | - addr[3] = 0; | |
322 | - } | |
323 | - /* We're Point-to-Point, so target it to the default DID */ | |
324 | - fcmd->did = fc->did; | |
325 | - PLND(("trying %04x%04x%04x%04x\n", addr[0], addr[1], addr[2], addr[3])) | |
326 | - return 0; | |
327 | -} | |
328 | - | |
329 | -static struct scsi_host_template driver_template = { | |
330 | - .name = "Sparc Storage Array 100/200", | |
331 | - .detect = pluto_detect, | |
332 | - .release = pluto_release, | |
333 | - .info = pluto_info, | |
334 | - .queuecommand = fcp_scsi_queuecommand, | |
335 | - .slave_configure = pluto_slave_configure, | |
336 | - .can_queue = PLUTO_CAN_QUEUE, | |
337 | - .this_id = -1, | |
338 | - .sg_tablesize = 1, | |
339 | - .cmd_per_lun = 1, | |
340 | - .use_clustering = ENABLE_CLUSTERING, | |
341 | - .eh_abort_handler = fcp_scsi_abort, | |
342 | - .eh_device_reset_handler = fcp_scsi_dev_reset, | |
343 | - .eh_host_reset_handler = fcp_scsi_host_reset, | |
344 | -}; | |
345 | - | |
346 | -#include "scsi_module.c" | |
347 | - | |
348 | -MODULE_LICENSE("GPL"); |
drivers/scsi/pluto.h
1 | -/* pluto.h: SparcSTORAGE Array SCSI host adapter driver definitions. | |
2 | - * | |
3 | - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | |
4 | - */ | |
5 | - | |
6 | -#ifndef _PLUTO_H | |
7 | -#define _PLUTO_H | |
8 | - | |
9 | -#include "../fc4/fcp_impl.h" | |
10 | - | |
11 | -struct pluto { | |
12 | - /* This must be first */ | |
13 | - fc_channel *fc; | |
14 | - char rev_str[5]; | |
15 | - char fw_rev_str[5]; | |
16 | - char serial_str[13]; | |
17 | -}; | |
18 | - | |
19 | -struct pluto_inquiry { | |
20 | - u8 dtype; | |
21 | - u8 removable:1, qualifier:7; | |
22 | - u8 iso:2, ecma:3, ansi:3; | |
23 | - u8 aenc:1, trmiop:1, :2, rdf:4; | |
24 | - u8 len; | |
25 | - u8 xxx1; | |
26 | - u8 xxx2; | |
27 | - u8 reladdr:1, wbus32:1, wbus16:1, sync:1, linked:1, :1, cmdque:1, softreset:1; | |
28 | - u8 vendor_id[8]; | |
29 | - u8 product_id[16]; | |
30 | - u8 revision[4]; | |
31 | - u8 fw_revision[4]; | |
32 | - u8 serial[12]; | |
33 | - u8 xxx3[2]; | |
34 | - u8 channels; | |
35 | - u8 targets; | |
36 | -}; | |
37 | - | |
38 | -/* This is the max number of outstanding SCSI commands per pluto */ | |
39 | -#define PLUTO_CAN_QUEUE 254 | |
40 | - | |
41 | -int pluto_detect(struct scsi_host_template *); | |
42 | -int pluto_release(struct Scsi_Host *); | |
43 | -const char * pluto_info(struct Scsi_Host *); | |
44 | -int pluto_slave_configure(struct scsi_device *); | |
45 | - | |
46 | -#endif /* !(_PLUTO_H) */ |