aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Wilcox <matthew@wil.cx>2007-10-16 01:05:07 -0400
committerJames Bottomley <jejb@mulgrave.localdomain>2007-10-17 21:53:55 -0400
commit1ecd3902c6e16c2445165b872c49e73770b72da7 (patch)
treecbfa9132a033801872003523e0d8e1be9dc23f77
parentd85714d81cc0408daddb68c10f7fd69eafe7c213 (diff)
[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>
-rw-r--r--arch/sparc64/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/fc4/Kconfig81
-rw-r--r--drivers/fc4/Makefile9
-rw-r--r--drivers/fc4/fc-al.h27
-rw-r--r--drivers/fc4/fc.c1146
-rw-r--r--drivers/fc4/fc.h230
-rw-r--r--drivers/fc4/fc_syms.c30
-rw-r--r--drivers/fc4/fcp.h94
-rw-r--r--drivers/fc4/fcp_impl.h164
-rw-r--r--drivers/fc4/soc.c764
-rw-r--r--drivers/fc4/soc.h301
-rw-r--r--drivers/fc4/socal.c904
-rw-r--r--drivers/fc4/socal.h314
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/fcal.c317
-rw-r--r--drivers/scsi/fcal.h27
-rw-r--r--drivers/scsi/pluto.c349
-rw-r--r--drivers/scsi/pluto.h47
19 files changed, 0 insertions, 4809 deletions
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 59c4d752d286..5cc8847221be 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -456,8 +456,6 @@ source "drivers/Kconfig"
456 456
457source "drivers/sbus/char/Kconfig" 457source "drivers/sbus/char/Kconfig"
458 458
459source "drivers/fc4/Kconfig"
460
461source "fs/Kconfig" 459source "fs/Kconfig"
462 460
463menu "Instrumentation Support" 461menu "Instrumentation Support"
diff --git a/drivers/Makefile b/drivers/Makefile
index 174c27eb4430..8c645bcfb3c5 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -34,7 +34,6 @@ obj-$(CONFIG_NUBUS) += nubus/
34obj-$(CONFIG_ATM) += atm/ 34obj-$(CONFIG_ATM) += atm/
35obj-y += macintosh/ 35obj-y += macintosh/
36obj-$(CONFIG_IDE) += ide/ 36obj-$(CONFIG_IDE) += ide/
37obj-$(CONFIG_FC4) += fc4/
38obj-$(CONFIG_SCSI) += scsi/ 37obj-$(CONFIG_SCSI) += scsi/
39obj-$(CONFIG_ATA) += ata/ 38obj-$(CONFIG_ATA) += ata/
40obj-$(CONFIG_FUSION) += message/ 39obj-$(CONFIG_FUSION) += message/
diff --git a/drivers/fc4/Kconfig b/drivers/fc4/Kconfig
deleted file mode 100644
index 345dbe6f10df..000000000000
--- a/drivers/fc4/Kconfig
+++ /dev/null
@@ -1,81 +0,0 @@
1#
2# FC4 device configuration
3#
4
5menu "Fibre Channel support"
6
7config 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
24comment "FC4 drivers"
25 depends on FC4
26
27config 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
39config 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
52comment "FC4 targets"
53 depends on FC4
54
55config 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
64config 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
76config SCSI_FCAL
77 prompt "Generic FC-AL disk driver"
78 depends on FC4!=n && SCSI && !SPARC
79
80endmenu
81
diff --git a/drivers/fc4/Makefile b/drivers/fc4/Makefile
deleted file mode 100644
index 0db3fbb553e9..000000000000
--- a/drivers/fc4/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
1#
2# Makefile for the Linux Fibre Channel device drivers.
3#
4
5fc4-objs := fc.o fc_syms.o
6
7obj-$(CONFIG_FC4) += fc4.o
8obj-$(CONFIG_FC4_SOC) += soc.o
9obj-$(CONFIG_FC4_SOCAL) += socal.o
diff --git a/drivers/fc4/fc-al.h b/drivers/fc4/fc-al.h
deleted file mode 100644
index 62d3ca436d72..000000000000
--- a/drivers/fc4/fc-al.h
+++ /dev/null
@@ -1,27 +0,0 @@
1/* fc-al.h: Definitions for Fibre Channel Arbitrated Loop topology.
2 *
3 * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
4 *
5 * Sources:
6 * Fibre Channel Arbitrated Loop (FC-AL), ANSI, Rev. 4.5, 1995
7 */
8
9#ifndef __FC_AL_H
10#define __FC_AL_H
11
12/* Loop initialization payloads */
13#define FC_AL_LISM 0x11010000 /* Select Master, 12B payload */
14#define FC_AL_LIFA 0x11020000 /* Fabric Assign AL_PA bitmap, 20B payload */
15#define FC_AL_LIPA 0x11030000 /* Previously Acquired AL_PA bitmap, 20B payload */
16#define FC_AL_LIHA 0x11040000 /* Hard Assigned AL_PA bitmap, 20B payload */
17#define FC_AL_LISA 0x11050000 /* Soft Assigned AL_PA bitmap, 20B payload */
18#define FC_AL_LIRP 0x11060000 /* Report AL_PA position map, 132B payload */
19#define FC_AL_LILP 0x11070000 /* Loop AL_PA position map, 132B payload */
20
21typedef struct {
22 u32 magic;
23 u8 len;
24 u8 alpa[127];
25} fc_al_posmap;
26
27#endif /* !(__FC_H) */
diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c
deleted file mode 100644
index 82de9e1adb1e..000000000000
--- a/drivers/fc4/fc.c
+++ /dev/null
@@ -1,1146 +0,0 @@
1/* fc.c: Generic Fibre Channel and FC4 SCSI driver.
2 *
3 * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
4 * Copyright (C) 1997,1998 Jirka Hanika (geo@ff.cuni.cz)
5 *
6 * There are two kinds of Fibre Channel adapters used in Linux. Either
7 * the adapter is "smart" and does all FC bookkeeping by itself and
8 * just presents a standard SCSI interface to the operating system
9 * (that's e.g. the case with Qlogic FC cards), or leaves most of the FC
10 * bookkeeping to the OS (e.g. soc, socal). Drivers for the former adapters
11 * will look like normal SCSI drivers (with the exception of max_id will be
12 * usually 127), the latter on the other side allows SCSI, IP over FC and other
13 * protocols. This driver tree is for the latter adapters.
14 *
15 * This file should support both Point-to-Point and Arbitrated Loop topologies.
16 *
17 * Sources:
18 * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994
19 * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995
20 * Fibre Channel Arbitrated Loop (FC-AL), Rev. 4.5, 1995
21 * Fibre Channel Private Loop SCSI Direct Attach (FC-PLDA), Rev. 2.1, 1997
22 */
23
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/jiffies.h>
27#include <linux/types.h>
28#include <linux/fcntl.h>
29#include <linux/interrupt.h>
30#include <linux/ptrace.h>
31#include <linux/ioport.h>
32#include <linux/in.h>
33#include <linux/slab.h>
34#include <linux/string.h>
35#include <linux/init.h>
36
37#include <asm/pgtable.h>
38#include <asm/irq.h>
39#include <asm/semaphore.h>
40#include "fcp_impl.h"
41#include <scsi/scsi_host.h>
42
43/* #define FCDEBUG */
44
45#define fc_printk printk ("%s: ", fc->name); printk
46
47#ifdef FCDEBUG
48#define FCD(x) fc_printk x;
49#define FCND(x) printk ("FC: "); printk x;
50#else
51#define FCD(x)
52#define FCND(x)
53#endif
54
55#ifdef __sparc__
56#define dma_alloc_consistent(d,s,p) sbus_alloc_consistent(d,s,p)
57#define dma_free_consistent(d,s,v,h) sbus_free_consistent(d,s,v,h)
58#define dma_map_single(d,v,s,dir) sbus_map_single(d,v,s,dir)
59#define dma_unmap_single(d,h,s,dir) sbus_unmap_single(d,h,s,dir)
60#define dma_map_sg(d,s,n,dir) sbus_map_sg(d,s,n,dir)
61#define dma_unmap_sg(d,s,n,dir) sbus_unmap_sg(d,s,n,dir)
62#else
63#define dma_alloc_consistent(d,s,p) pci_alloc_consistent(d,s,p)
64#define dma_free_consistent(d,s,v,h) pci_free_consistent(d,s,v,h)
65#define dma_map_single(d,v,s,dir) pci_map_single(d,v,s,dir)
66#define dma_unmap_single(d,h,s,dir) pci_unmap_single(d,h,s,dir)
67#define dma_map_sg(d,s,n,dir) pci_map_sg(d,s,n,dir)
68#define dma_unmap_sg(d,s,n,dir) pci_unmap_sg(d,s,n,dir)
69#endif
70
71#define FCP_CMND(SCpnt) ((fcp_cmnd *)&(SCpnt->SCp))
72#define FC_SCMND(SCpnt) ((fc_channel *)(SCpnt->device->host->hostdata[0]))
73#define SC_FCMND(fcmnd) ((struct scsi_cmnd *)((long)fcmnd - (long)&(((struct scsi_cmnd *)0)->SCp)))
74
75static int fcp_scsi_queue_it(fc_channel *, struct scsi_cmnd *, fcp_cmnd *, int);
76void fcp_queue_empty(fc_channel *);
77
78static 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
92static 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
104fc_channel *fc_channels = NULL;
105
106#define LSMAGIC 620829043
107typedef 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
120typedef 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
131typedef struct {
132 /* Must be first */
133 struct semaphore sem;
134 int magic;
135 int status;
136 struct timer_list timer;
137} lse;
138
139static void fcp_login_timeout(unsigned long data)
140{
141 ls *l = (ls *)data;
142 FCND(("Login timeout\n"))
143 up(&l->sem);
144}
145
146static 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
243static 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
336void 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
381static void fcp_scsi_done(struct scsi_cmnd *SCpnt);
382
383static 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
458void 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
515void 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
526int 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 }
637all_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
654int 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
703int 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
727void 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
755static void fcp_scsi_done(struct scsi_cmnd *SCpnt)
756{
757 if (FCP_CMND(SCpnt)->done)
758 FCP_CMND(SCpnt)->done(SCpnt);
759}
760
761static 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
830int 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
854void 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
867int 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
904void 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
915int 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
993static 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
1014int 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
1026static 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
1038static 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
1094int 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
1123typedef struct {
1124 unsigned int code;
1125 unsigned params[4];
1126} prli;
1127
1128int 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
1145MODULE_LICENSE("GPL");
1146
diff --git a/drivers/fc4/fc.h b/drivers/fc4/fc.h
deleted file mode 100644
index 13f89d4c8cb9..000000000000
--- a/drivers/fc4/fc.h
+++ /dev/null
@@ -1,230 +0,0 @@
1/* fc.h: Definitions for Fibre Channel Physical and Signaling Interface.
2 *
3 * Copyright (C) 1996-1997,1999 Jakub Jelinek (jj@ultra.linux.cz)
4 *
5 * Sources:
6 * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994
7 * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995
8 */
9
10#ifndef __FC_H
11#define __FC_H
12
13/* World Wide Name */
14#define NAAID_IEEE 1
15#define NAAID_IEEE_EXT 2
16#define NAAID_LOCAL 3
17#define NAAID_IP 4
18#define NAAID_IEEE_REG 5
19#define NAAID_IEEE_REG_EXT 6
20#define NAAID_CCITT 12
21#define NAAID_CCITT_GRP 14
22
23/* This is NAAID_IEEE_EXT scheme */
24typedef 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
97typedef 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 */
125typedef 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
195typedef 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
207typedef 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 */
220typedef struct {
221 u32 code;
222 common_svc_parm common;
223 fc_wwn nport_wwn;
224 fc_wwn node_wwn;
225 svc_parm class1;
226 svc_parm class2;
227 svc_parm class3;
228} logi;
229
230#endif /* !(__FC_H) */
diff --git a/drivers/fc4/fc_syms.c b/drivers/fc4/fc_syms.c
deleted file mode 100644
index bd3918ddf7ac..000000000000
--- a/drivers/fc4/fc_syms.c
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * We should not even be trying to compile this if we are not doing
3 * a module.
4 */
5#include <linux/module.h>
6
7#ifdef CONFIG_MODULES
8
9#include <linux/types.h>
10#include <linux/string.h>
11#include <linux/kernel.h>
12
13#include "fcp_impl.h"
14
15EXPORT_SYMBOL(fcp_init);
16EXPORT_SYMBOL(fcp_release);
17EXPORT_SYMBOL(fcp_queue_empty);
18EXPORT_SYMBOL(fcp_receive_solicited);
19EXPORT_SYMBOL(fc_channels);
20EXPORT_SYMBOL(fcp_state_change);
21EXPORT_SYMBOL(fc_do_plogi);
22EXPORT_SYMBOL(fc_do_prli);
23
24/* SCSI stuff */
25EXPORT_SYMBOL(fcp_scsi_queuecommand);
26EXPORT_SYMBOL(fcp_scsi_abort);
27EXPORT_SYMBOL(fcp_scsi_dev_reset);
28EXPORT_SYMBOL(fcp_scsi_host_reset);
29
30#endif /* CONFIG_MODULES */
diff --git a/drivers/fc4/fcp.h b/drivers/fc4/fcp.h
deleted file mode 100644
index 6aa34a7a4c11..000000000000
--- a/drivers/fc4/fcp.h
+++ /dev/null
@@ -1,94 +0,0 @@
1/* fcp.h: Definitions for Fibre Channel Protocol.
2 *
3 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
4 *
5 */
6
7#ifndef __FCP_H
8#define __FCP_H
9
10/* FCP addressing is hierarchical with up to 4 layers, MS first.
11 Exact meaning of the addresses is up to the vendor */
12
13/* fcp_cntl field */
14#define FCP_CNTL_WRITE 0x00000001 /* Initiator write */
15#define FCP_CNTL_READ 0x00000002 /* Initiator read */
16#define FCP_CNTL_ABORT_TSK 0x00000200 /* Abort task set */
17#define FCP_CNTL_CLR_TASK 0x00000400 /* Clear task set */
18#define FCP_CNTL_RESET 0x00002000 /* Reset */
19#define FCP_CNTL_CLR_ACA 0x00004000 /* Clear ACA */
20#define FCP_CNTL_KILL_TASK 0x00008000 /* Terminate task */
21#define FCP_CNTL_QTYPE_MASK 0x00070000 /* Tagged queueing type */
22#define FCP_CNTL_QTYPE_SIMPLE 0x00000000
23#define FCP_CNTL_QTYPE_HEAD_OF_Q 0x00010000
24#define FCP_CNTL_QTYPE_ORDERED 0x00020000
25#define FCP_CNTL_QTYPE_ACA_Q_TAG 0x00040000
26#define FCP_CNTL_QTYPE_UNTAGGED 0x00050000
27
28typedef 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
41typedef 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
86typedef struct {
87 u8 rsp_info_type;
88 u8 xxx;
89 u16 isp_status;
90 u16 isp_state_flags;
91 u16 isp_stat_flags;
92} fcp_scsi_err;
93
94#endif /* !(__FCP_H) */
diff --git a/drivers/fc4/fcp_impl.h b/drivers/fc4/fcp_impl.h
deleted file mode 100644
index 506338a461ba..000000000000
--- a/drivers/fc4/fcp_impl.h
+++ /dev/null
@@ -1,164 +0,0 @@
1/* fcp_impl.h: Generic SCSI on top of FC4 - our interface defines.
2 *
3 * Copyright (C) 1997-1999 Jakub Jelinek (jj@ultra.linux.cz)
4 * Copyright (C) 1998 Jirka Hanika (geo@ff.cuni.cz)
5 */
6
7#ifndef _FCP_SCSI_H
8#define _FCP_SCSI_H
9
10#include <linux/types.h>
11#include "../scsi/scsi.h"
12
13#include "fc.h"
14#include "fcp.h"
15#include "fc-al.h"
16
17#include <asm/io.h>
18#ifdef __sparc__
19#include <asm/sbus.h>
20#endif
21
22/* 0 or 1 */
23#define FCP_SCSI_USE_NEW_EH_CODE 0
24
25#define FC_CLASS_OUTBOUND 0x01
26#define FC_CLASS_INBOUND 0x02
27#define FC_CLASS_SIMPLE 0x03
28#define FC_CLASS_IO_WRITE 0x04
29#define FC_CLASS_IO_READ 0x05
30#define FC_CLASS_UNSOLICITED 0x06
31#define FC_CLASS_OFFLINE 0x08
32
33#define PROTO_OFFLINE 0x02
34#define PROTO_REPORT_AL_MAP 0x03
35#define PROTO_FORCE_LIP 0x06
36
37struct _fc_channel;
38
39typedef 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
61typedef struct {
62 unsigned int len;
63 unsigned char list[0];
64} fcp_posmap;
65
66typedef 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
111extern 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
143void fcp_queue_empty(fc_channel *);
144int fcp_init(fc_channel *);
145void fcp_release(fc_channel *fc_chain, int count);
146void fcp_receive_solicited(fc_channel *, int, int, int, fc_hdr *);
147void fcp_state_change(fc_channel *, int);
148int fc_do_plogi(fc_channel *, unsigned char, fc_wwn *, fc_wwn *);
149int 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
158int fcp_scsi_queuecommand(struct scsi_cmnd *,
159 void (* done) (struct scsi_cmnd *));
160int fcp_scsi_abort(struct scsi_cmnd *);
161int fcp_scsi_dev_reset(struct scsi_cmnd *);
162int fcp_scsi_host_reset(struct scsi_cmnd *);
163
164#endif /* !(_FCP_SCSI_H) */
diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c
deleted file mode 100644
index d517734462e6..000000000000
--- a/drivers/fc4/soc.c
+++ /dev/null
@@ -1,764 +0,0 @@
1/* soc.c: Sparc SUNW,soc (Serial Optical Channel) Fibre Channel Sbus adapter support.
2 *
3 * Copyright (C) 1996,1997,1999 Jakub Jelinek (jj@ultra.linux.cz)
4 * Copyright (C) 1997,1998 Jirka Hanika (geo@ff.cuni.cz)
5 *
6 * Sources:
7 * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994
8 * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995
9 *
10 * Supported hardware:
11 * Tested on SOC sbus card bought with SS1000 in Linux running on SS5 and Ultra1.
12 * For SOC sbus cards, you have to make sure your FCode is 1.52 or later.
13 * If you have older FCode, you should try to upgrade or get SOC microcode from Sun
14 * (the microcode is present in Solaris soc driver as well). In that case you need
15 * to #define HAVE_SOC_UCODE and format the microcode into soc_asm.c. For the exact
16 * format mail me and I will tell you. I cannot offer you the actual microcode though,
17 * unless Sun confirms they don't mind.
18 */
19
20static 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)
63struct soc *socs = NULL;
64
65static 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
71static 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
81static 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
105static 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
166static 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
185static 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 };
306update_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
336static 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
356static 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
520static 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 */
531static 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
548static 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
712static 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
736static 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
762module_init(soc_probe);
763module_exit(soc_cleanup);
764MODULE_LICENSE("GPL");
diff --git a/drivers/fc4/soc.h b/drivers/fc4/soc.h
deleted file mode 100644
index d38cf5b28eed..000000000000
--- a/drivers/fc4/soc.h
+++ /dev/null
@@ -1,301 +0,0 @@
1/* soc.h: Definitions for Sparc SUNW,soc Fibre Channel Sbus driver.
2 *
3 * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
4 */
5
6#ifndef __SOC_H
7#define __SOC_H
8
9#include "fc.h"
10#include "fcp.h"
11#include "fcp_impl.h"
12
13/* Hardware register offsets and constants first {{{ */
14#define CFG 0x00UL /* Config Register */
15#define SAE 0x04UL /* Slave Access Error Register */
16#define CMD 0x08UL /* Command and Status Register */
17#define IMASK 0x0cUL /* Interrupt Mask Register */
18
19/* Config Register */
20#define SOC_CFG_EXT_RAM_BANK_MASK 0x07000000
21#define SOC_CFG_EEPROM_BANK_MASK 0x00030000
22#define SOC_CFG_BURST64_MASK 0x00000700
23#define SOC_CFG_SBUS_PARITY_TEST 0x00000020
24#define SOC_CFG_SBUS_PARITY_CHECK 0x00000010
25#define SOC_CFG_SBUS_ENHANCED 0x00000008
26#define SOC_CFG_BURST_MASK 0x00000007
27/* Bursts */
28#define SOC_CFG_BURST_4 0x00000000
29#define SOC_CFG_BURST_16 0x00000004
30#define SOC_CFG_BURST_32 0x00000005
31#define SOC_CFG_BURST_64 0x00000006
32
33/* Slave Access Error Register */
34#define SOC_SAE_ALIGNMENT 0x00000004
35#define SOC_SAE_UNSUPPORTED 0x00000002
36#define SOC_SAE_PARITY 0x00000001
37
38/* Command & Status Register */
39#define SOC_CMD_RSP_QALL 0x000f0000
40#define SOC_CMD_RSP_Q0 0x00010000
41#define SOC_CMD_RSP_Q1 0x00020000
42#define SOC_CMD_RSP_Q2 0x00040000
43#define SOC_CMD_RSP_Q3 0x00080000
44#define SOC_CMD_REQ_QALL 0x00000f00
45#define SOC_CMD_REQ_Q0 0x00000100
46#define SOC_CMD_REQ_Q1 0x00000200
47#define SOC_CMD_REQ_Q2 0x00000400
48#define SOC_CMD_REQ_Q3 0x00000800
49#define SOC_CMD_SAE 0x00000080
50#define SOC_CMD_INTR_PENDING 0x00000008
51#define SOC_CMD_NON_QUEUED 0x00000004
52#define SOC_CMD_IDLE 0x00000002
53#define SOC_CMD_SOFT_RESET 0x00000001
54
55/* Interrupt Mask Register */
56#define SOC_IMASK_RSP_QALL 0x000f0000
57#define SOC_IMASK_RSP_Q0 0x00010000
58#define SOC_IMASK_RSP_Q1 0x00020000
59#define SOC_IMASK_RSP_Q2 0x00040000
60#define SOC_IMASK_RSP_Q3 0x00080000
61#define SOC_IMASK_REQ_QALL 0x00000f00
62#define SOC_IMASK_REQ_Q0 0x00000100
63#define SOC_IMASK_REQ_Q1 0x00000200
64#define SOC_IMASK_REQ_Q2 0x00000400
65#define SOC_IMASK_REQ_Q3 0x00000800
66#define SOC_IMASK_SAE 0x00000080
67#define SOC_IMASK_NON_QUEUED 0x00000004
68
69#define SOC_INTR(s, cmd) \
70 (((cmd & SOC_CMD_RSP_QALL) | ((~cmd) & SOC_CMD_REQ_QALL)) \
71 & s->imask)
72
73#define SOC_SETIMASK(s, i) \
74do { (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
84typedef void __iomem *xram_p;
85
86/* Get 32bit number from XRAM */
87static 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 */
94static inline u32 xram_get_32low(xram_p x)
95{
96 return (u32) sbus_readw(x + 0x02UL);
97}
98
99static inline u16 xram_get_16(xram_p x)
100{
101 return sbus_readw(x);
102}
103
104static 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
114static 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
126static 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
138static 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
149typedef 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
169typedef struct {
170 u32 token;
171 u16 flags;
172 u8 class;
173 u8 segcnt;
174 u32 bytecnt;
175} soc_hdr;
176
177typedef 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
198typedef 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
228typedef 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
252struct soc;
253
254typedef struct {
255 /* This must come first */
256 fc_channel fc;
257 struct soc *s;
258 u16 flags;
259 u16 mask;
260} soc_port;
261
262typedef 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
271typedef 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
280struct soc {
281 spinlock_t lock;
282 soc_port port[2]; /* Every SOC has one or two FC ports */
283 soc_cq_req req[2]; /* Request CQs */
284 soc_cq_rsp rsp[2]; /* Response CQs */
285 int soc_no;
286 void __iomem *regs;
287 xram_p xram;
288 fc_wwn wwn;
289 u32 imask; /* Our copy of regs->imask */
290 u32 cfg; /* Our copy of regs->cfg */
291 char serv_params[80];
292 struct soc *next;
293 int curr_port; /* Which port will have priority to fcp_queue_empty */
294
295 soc_req *req_cpu;
296 u32 req_dvma;
297};
298
299/* }}} */
300
301#endif /* !(__SOC_H) */
diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c
deleted file mode 100644
index c903ebfab526..000000000000
--- a/drivers/fc4/socal.c
+++ /dev/null
@@ -1,904 +0,0 @@
1/* socal.c: Sparc SUNW,socal (SOC+) Fibre Channel Sbus adapter support.
2 *
3 * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
4 *
5 * Sources:
6 * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994
7 * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995
8 * SOC+ Programming Guide 0.1
9 * Fibre Channel Arbitrated Loop (FC-AL), dpANS rev. 4.5, 1995
10 *
11 * Supported hardware:
12 * On-board SOC+ adapters of Ultra Enterprise servers and sun4d.
13 */
14
15static 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)
60struct socal *socals = NULL;
61
62static 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
72static 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
84static 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
94static 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
100static 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
110static 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
134static 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
226static 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
243static 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 };
376update_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
406static 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
436static 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
606static 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 */
620static 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
657static 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
849static 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
875static 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
902module_init(socal_probe);
903module_exit(socal_cleanup);
904MODULE_LICENSE("GPL");
diff --git a/drivers/fc4/socal.h b/drivers/fc4/socal.h
deleted file mode 100644
index 774edf68e4d2..000000000000
--- a/drivers/fc4/socal.h
+++ /dev/null
@@ -1,314 +0,0 @@
1/* socal.h: Definitions for Sparc SUNW,socal (SOC+) Fibre Channel Sbus driver.
2 *
3 * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
4 */
5
6#ifndef __SOCAL_H
7#define __SOCAL_H
8
9#include "fc.h"
10#include "fcp.h"
11#include "fcp_impl.h"
12
13/* Hardware register offsets and constants first {{{ */
14#define CFG 0x00UL
15#define SAE 0x04UL
16#define CMD 0x08UL
17#define IMASK 0x0cUL
18#define REQP 0x10UL
19#define RESP 0x14UL
20
21/* Config Register */
22#define SOCAL_CFG_EXT_RAM_BANK_MASK 0x07000000
23#define SOCAL_CFG_EEPROM_BANK_MASK 0x00030000
24#define SOCAL_CFG_BURST64_MASK 0x00000700
25#define SOCAL_CFG_SBUS_PARITY_TEST 0x00000020
26#define SOCAL_CFG_SBUS_PARITY_CHECK 0x00000010
27#define SOCAL_CFG_SBUS_ENHANCED 0x00000008
28#define SOCAL_CFG_BURST_MASK 0x00000007
29/* Bursts */
30#define SOCAL_CFG_BURST_4 0x00000000
31#define SOCAL_CFG_BURST_8 0x00000003
32#define SOCAL_CFG_BURST_16 0x00000004
33#define SOCAL_CFG_BURST_32 0x00000005
34#define SOCAL_CFG_BURST_64 0x00000006
35#define SOCAL_CFG_BURST_128 0x00000007
36
37/* Slave Access Error Register */
38#define SOCAL_SAE_ALIGNMENT 0x00000004
39#define SOCAL_SAE_UNSUPPORTED 0x00000002
40#define SOCAL_SAE_PARITY 0x00000001
41
42/* Command & Status Register */
43#define SOCAL_CMD_RSP_QALL 0x000f0000
44#define SOCAL_CMD_RSP_Q0 0x00010000
45#define SOCAL_CMD_RSP_Q1 0x00020000
46#define SOCAL_CMD_RSP_Q2 0x00040000
47#define SOCAL_CMD_RSP_Q3 0x00080000
48#define SOCAL_CMD_REQ_QALL 0x00000f00
49#define SOCAL_CMD_REQ_Q0 0x00000100
50#define SOCAL_CMD_REQ_Q1 0x00000200
51#define SOCAL_CMD_REQ_Q2 0x00000400
52#define SOCAL_CMD_REQ_Q3 0x00000800
53#define SOCAL_CMD_SAE 0x00000080
54#define SOCAL_CMD_INTR_PENDING 0x00000008
55#define SOCAL_CMD_NON_QUEUED 0x00000004
56#define SOCAL_CMD_IDLE 0x00000002
57#define SOCAL_CMD_SOFT_RESET 0x00000001
58
59/* Interrupt Mask Register */
60#define SOCAL_IMASK_RSP_QALL 0x000f0000
61#define SOCAL_IMASK_RSP_Q0 0x00010000
62#define SOCAL_IMASK_RSP_Q1 0x00020000
63#define SOCAL_IMASK_RSP_Q2 0x00040000
64#define SOCAL_IMASK_RSP_Q3 0x00080000
65#define SOCAL_IMASK_REQ_QALL 0x00000f00
66#define SOCAL_IMASK_REQ_Q0 0x00000100
67#define SOCAL_IMASK_REQ_Q1 0x00000200
68#define SOCAL_IMASK_REQ_Q2 0x00000400
69#define SOCAL_IMASK_REQ_Q3 0x00000800
70#define SOCAL_IMASK_SAE 0x00000080
71#define SOCAL_IMASK_NON_QUEUED 0x00000004
72
73#define SOCAL_INTR(s, cmd) \
74 (((cmd & SOCAL_CMD_RSP_QALL) | ((~cmd) & SOCAL_CMD_REQ_QALL)) \
75 & s->imask)
76
77#define SOCAL_SETIMASK(s, i) \
78do { (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
96typedef 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
117typedef struct {
118 u32 token;
119 u16 flags;
120 u8 class;
121 u8 segcnt;
122 u32 bytecnt;
123} socal_hdr;
124
125typedef 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
155typedef 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
191typedef 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
204typedef 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
224typedef 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
245typedef 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
273struct socal;
274
275typedef struct {
276 /* This must come first */
277 fc_channel fc;
278 struct socal *s;
279 u16 flags;
280 u16 mask;
281} socal_port;
282
283typedef 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
292struct 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) */
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 6141389dcdb2..2e6129f13d38 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -115,7 +115,6 @@ obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o
115obj-$(CONFIG_BLK_DEV_IDESCSI) += ide-scsi.o 115obj-$(CONFIG_BLK_DEV_IDESCSI) += ide-scsi.o
116obj-$(CONFIG_SCSI_MESH) += mesh.o 116obj-$(CONFIG_SCSI_MESH) += mesh.o
117obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o 117obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o
118obj-$(CONFIG_SCSI_PLUTO) += pluto.o
119obj-$(CONFIG_SCSI_DECNCR) += NCR53C9x.o dec_esp.o 118obj-$(CONFIG_SCSI_DECNCR) += NCR53C9x.o dec_esp.o
120obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o 119obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o
121obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o 120obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o
@@ -123,7 +122,6 @@ obj-$(CONFIG_SCSI_PPA) += ppa.o
123obj-$(CONFIG_SCSI_IMM) += imm.o 122obj-$(CONFIG_SCSI_IMM) += imm.o
124obj-$(CONFIG_JAZZ_ESP) += esp_scsi.o jazz_esp.o 123obj-$(CONFIG_JAZZ_ESP) += esp_scsi.o jazz_esp.o
125obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o 124obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o
126obj-$(CONFIG_SCSI_FCAL) += fcal.o
127obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o 125obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o
128obj-$(CONFIG_SCSI_SNI_53C710) += 53c700.o sni_53c710.o 126obj-$(CONFIG_SCSI_SNI_53C710) += 53c700.o sni_53c710.o
129obj-$(CONFIG_SCSI_NSP32) += nsp32.o 127obj-$(CONFIG_SCSI_NSP32) += nsp32.o
diff --git a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c
deleted file mode 100644
index c4e16c0775de..000000000000
--- a/drivers/scsi/fcal.c
+++ /dev/null
@@ -1,317 +0,0 @@
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
41static unsigned char alpa2target[] = {
420x7e, 0x7d, 0x7c, 0xff, 0x7b, 0xff, 0xff, 0xff, 0x7a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79,
430x78, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x76, 0xff, 0xff, 0x75, 0xff, 0x74, 0x73, 0x72,
440xff, 0xff, 0xff, 0x71, 0xff, 0x70, 0x6f, 0x6e, 0xff, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0xff,
450xff, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0xff, 0xff, 0x61, 0x60, 0xff, 0x5f, 0xff, 0xff, 0xff,
460xff, 0xff, 0xff, 0x5e, 0xff, 0x5d, 0x5c, 0x5b, 0xff, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0xff,
470xff, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0xff, 0xff, 0x4e, 0x4d, 0xff, 0x4c, 0xff, 0xff, 0xff,
480xff, 0xff, 0xff, 0x4b, 0xff, 0x4a, 0x49, 0x48, 0xff, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0xff,
490xff, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0xff, 0xff, 0x3b, 0x3a, 0xff, 0x39, 0xff, 0xff, 0xff,
500x38, 0x37, 0x36, 0xff, 0x35, 0xff, 0xff, 0xff, 0x34, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x33,
510x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x30, 0xff, 0xff, 0x2f, 0xff, 0x2e, 0x2d, 0x2c,
520xff, 0xff, 0xff, 0x2b, 0xff, 0x2a, 0x29, 0x28, 0xff, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0xff,
530xff, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0xff, 0xff, 0x1b, 0x1a, 0xff, 0x19, 0xff, 0xff, 0xff,
540xff, 0xff, 0xff, 0x18, 0xff, 0x17, 0x16, 0x15, 0xff, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0xff,
550xff, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0xff, 0xff, 0x08, 0x07, 0xff, 0x06, 0xff, 0xff, 0xff,
560x05, 0x04, 0x03, 0xff, 0x02, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
57};
58
59static unsigned char target2alpa[] = {
600xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce,
610xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5, 0xb4, 0xb3,
620xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b,
630x98, 0x97, 0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79, 0x76, 0x75, 0x74, 0x73,
640x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
650x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x47, 0x46, 0x45, 0x43, 0x3c,
660x3a, 0x39, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x27, 0x26,
670x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17, 0x10, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x00
68};
69
70static int fcal_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd);
71
72int 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... */
91int __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
194int 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
211int 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 */
280static 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
298static 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
316MODULE_LICENSE("GPL");
317
diff --git a/drivers/scsi/fcal.h b/drivers/scsi/fcal.h
deleted file mode 100644
index 7ff2c3494f9e..000000000000
--- a/drivers/scsi/fcal.h
+++ /dev/null
@@ -1,27 +0,0 @@
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
11struct 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
23int fcal_detect(struct scsi_host_template *);
24int fcal_release(struct Scsi_Host *);
25int fcal_slave_configure(struct scsi_device *);
26
27#endif /* !(_FCAL_H) */
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
deleted file mode 100644
index 0363c1cd68c1..000000000000
--- a/drivers/scsi/pluto.c
+++ /dev/null
@@ -1,349 +0,0 @@
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
45static 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;
52static int fcscount __initdata = 0;
53static atomic_t fcss __initdata = ATOMIC_INIT(0);
54static DECLARE_COMPLETION(fc_detect_complete);
55
56static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd);
57
58static void __init pluto_detect_done(Scsi_Cmnd *SCpnt)
59{
60 /* Do nothing */
61}
62
63static 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
70int 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. */
89int __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
266int 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
280const 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 */
307static 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
329static 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
348MODULE_LICENSE("GPL");
349
diff --git a/drivers/scsi/pluto.h b/drivers/scsi/pluto.h
deleted file mode 100644
index 5da20616ac36..000000000000
--- a/drivers/scsi/pluto.h
+++ /dev/null
@@ -1,47 +0,0 @@
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
11struct 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
19struct 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
41int pluto_detect(struct scsi_host_template *);
42int pluto_release(struct Scsi_Host *);
43const char * pluto_info(struct Scsi_Host *);
44int pluto_slave_configure(struct scsi_device *);
45
46#endif /* !(_PLUTO_H) */
47