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