Commit e05620073625935290120be93a6214b1b52ae34f
Committed by
James Bottomley
1 parent
b277d2aa9a
Exists in
master
and in
7 other branches
[SCSI] fcoe: add support to FCoE offload support in fcoe_sw through net_device
This adds implementation of ddp_setup()/ddp_done() in fcoe_sw for its fcoe_sw_libfc_fcn_templ. Signed-off-by: Yi Zou <yi.zou@intel.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Showing 1 changed file with 38 additions and 0 deletions Inline Diff
drivers/scsi/fcoe/fcoe_sw.c
1 | /* | 1 | /* |
2 | * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. | 2 | * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms and conditions of the GNU General Public License, | 5 | * under the terms and conditions of the GNU General Public License, |
6 | * version 2, as published by the Free Software Foundation. | 6 | * version 2, as published by the Free Software Foundation. |
7 | * | 7 | * |
8 | * This program is distributed in the hope it will be useful, but WITHOUT | 8 | * This program is distributed in the hope it will be useful, but WITHOUT |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
11 | * more details. | 11 | * more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License along with | 13 | * You should have received a copy of the GNU General Public License along with |
14 | * this program; if not, write to the Free Software Foundation, Inc., | 14 | * this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | 15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. |
16 | * | 16 | * |
17 | * Maintained at www.Open-FCoE.org | 17 | * Maintained at www.Open-FCoE.org |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/version.h> | 21 | #include <linux/version.h> |
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
26 | #include <linux/netdevice.h> | 26 | #include <linux/netdevice.h> |
27 | #include <linux/etherdevice.h> | 27 | #include <linux/etherdevice.h> |
28 | #include <linux/if_vlan.h> | 28 | #include <linux/if_vlan.h> |
29 | #include <net/rtnetlink.h> | 29 | #include <net/rtnetlink.h> |
30 | 30 | ||
31 | #include <scsi/fc/fc_els.h> | 31 | #include <scsi/fc/fc_els.h> |
32 | #include <scsi/fc/fc_encaps.h> | 32 | #include <scsi/fc/fc_encaps.h> |
33 | #include <scsi/fc/fc_fs.h> | 33 | #include <scsi/fc/fc_fs.h> |
34 | #include <scsi/scsi_transport.h> | 34 | #include <scsi/scsi_transport.h> |
35 | #include <scsi/scsi_transport_fc.h> | 35 | #include <scsi/scsi_transport_fc.h> |
36 | 36 | ||
37 | #include <scsi/libfc.h> | 37 | #include <scsi/libfc.h> |
38 | #include <scsi/libfcoe.h> | 38 | #include <scsi/libfcoe.h> |
39 | #include <scsi/fc_transport_fcoe.h> | 39 | #include <scsi/fc_transport_fcoe.h> |
40 | 40 | ||
41 | #define FCOE_SW_VERSION "0.1" | 41 | #define FCOE_SW_VERSION "0.1" |
42 | #define FCOE_SW_NAME "fcoesw" | 42 | #define FCOE_SW_NAME "fcoesw" |
43 | #define FCOE_SW_VENDOR "Open-FCoE.org" | 43 | #define FCOE_SW_VENDOR "Open-FCoE.org" |
44 | 44 | ||
45 | #define FCOE_MAX_LUN 255 | 45 | #define FCOE_MAX_LUN 255 |
46 | #define FCOE_MAX_FCP_TARGET 256 | 46 | #define FCOE_MAX_FCP_TARGET 256 |
47 | 47 | ||
48 | #define FCOE_MAX_OUTSTANDING_COMMANDS 1024 | 48 | #define FCOE_MAX_OUTSTANDING_COMMANDS 1024 |
49 | 49 | ||
50 | #define FCOE_MIN_XID 0x0001 /* the min xid supported by fcoe_sw */ | 50 | #define FCOE_MIN_XID 0x0001 /* the min xid supported by fcoe_sw */ |
51 | #define FCOE_MAX_XID 0x07ef /* the max xid supported by fcoe_sw */ | 51 | #define FCOE_MAX_XID 0x07ef /* the max xid supported by fcoe_sw */ |
52 | 52 | ||
53 | static struct scsi_transport_template *scsi_transport_fcoe_sw; | 53 | static struct scsi_transport_template *scsi_transport_fcoe_sw; |
54 | 54 | ||
55 | struct fc_function_template fcoe_sw_transport_function = { | 55 | struct fc_function_template fcoe_sw_transport_function = { |
56 | .show_host_node_name = 1, | 56 | .show_host_node_name = 1, |
57 | .show_host_port_name = 1, | 57 | .show_host_port_name = 1, |
58 | .show_host_supported_classes = 1, | 58 | .show_host_supported_classes = 1, |
59 | .show_host_supported_fc4s = 1, | 59 | .show_host_supported_fc4s = 1, |
60 | .show_host_active_fc4s = 1, | 60 | .show_host_active_fc4s = 1, |
61 | .show_host_maxframe_size = 1, | 61 | .show_host_maxframe_size = 1, |
62 | 62 | ||
63 | .show_host_port_id = 1, | 63 | .show_host_port_id = 1, |
64 | .show_host_supported_speeds = 1, | 64 | .show_host_supported_speeds = 1, |
65 | .get_host_speed = fc_get_host_speed, | 65 | .get_host_speed = fc_get_host_speed, |
66 | .show_host_speed = 1, | 66 | .show_host_speed = 1, |
67 | .show_host_port_type = 1, | 67 | .show_host_port_type = 1, |
68 | .get_host_port_state = fc_get_host_port_state, | 68 | .get_host_port_state = fc_get_host_port_state, |
69 | .show_host_port_state = 1, | 69 | .show_host_port_state = 1, |
70 | .show_host_symbolic_name = 1, | 70 | .show_host_symbolic_name = 1, |
71 | 71 | ||
72 | .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), | 72 | .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), |
73 | .show_rport_maxframe_size = 1, | 73 | .show_rport_maxframe_size = 1, |
74 | .show_rport_supported_classes = 1, | 74 | .show_rport_supported_classes = 1, |
75 | 75 | ||
76 | .show_host_fabric_name = 1, | 76 | .show_host_fabric_name = 1, |
77 | .show_starget_node_name = 1, | 77 | .show_starget_node_name = 1, |
78 | .show_starget_port_name = 1, | 78 | .show_starget_port_name = 1, |
79 | .show_starget_port_id = 1, | 79 | .show_starget_port_id = 1, |
80 | .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, | 80 | .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, |
81 | .show_rport_dev_loss_tmo = 1, | 81 | .show_rport_dev_loss_tmo = 1, |
82 | .get_fc_host_stats = fc_get_host_stats, | 82 | .get_fc_host_stats = fc_get_host_stats, |
83 | .issue_fc_host_lip = fcoe_reset, | 83 | .issue_fc_host_lip = fcoe_reset, |
84 | 84 | ||
85 | .terminate_rport_io = fc_rport_terminate_io, | 85 | .terminate_rport_io = fc_rport_terminate_io, |
86 | }; | 86 | }; |
87 | 87 | ||
88 | static struct scsi_host_template fcoe_sw_shost_template = { | 88 | static struct scsi_host_template fcoe_sw_shost_template = { |
89 | .module = THIS_MODULE, | 89 | .module = THIS_MODULE, |
90 | .name = "FCoE Driver", | 90 | .name = "FCoE Driver", |
91 | .proc_name = FCOE_SW_NAME, | 91 | .proc_name = FCOE_SW_NAME, |
92 | .queuecommand = fc_queuecommand, | 92 | .queuecommand = fc_queuecommand, |
93 | .eh_abort_handler = fc_eh_abort, | 93 | .eh_abort_handler = fc_eh_abort, |
94 | .eh_device_reset_handler = fc_eh_device_reset, | 94 | .eh_device_reset_handler = fc_eh_device_reset, |
95 | .eh_host_reset_handler = fc_eh_host_reset, | 95 | .eh_host_reset_handler = fc_eh_host_reset, |
96 | .slave_alloc = fc_slave_alloc, | 96 | .slave_alloc = fc_slave_alloc, |
97 | .change_queue_depth = fc_change_queue_depth, | 97 | .change_queue_depth = fc_change_queue_depth, |
98 | .change_queue_type = fc_change_queue_type, | 98 | .change_queue_type = fc_change_queue_type, |
99 | .this_id = -1, | 99 | .this_id = -1, |
100 | .cmd_per_lun = 32, | 100 | .cmd_per_lun = 32, |
101 | .can_queue = FCOE_MAX_OUTSTANDING_COMMANDS, | 101 | .can_queue = FCOE_MAX_OUTSTANDING_COMMANDS, |
102 | .use_clustering = ENABLE_CLUSTERING, | 102 | .use_clustering = ENABLE_CLUSTERING, |
103 | .sg_tablesize = SG_ALL, | 103 | .sg_tablesize = SG_ALL, |
104 | .max_sectors = 0xffff, | 104 | .max_sectors = 0xffff, |
105 | }; | 105 | }; |
106 | 106 | ||
107 | /** | 107 | /** |
108 | * fcoe_sw_lport_config() - sets up the fc_lport | 108 | * fcoe_sw_lport_config() - sets up the fc_lport |
109 | * @lp: ptr to the fc_lport | 109 | * @lp: ptr to the fc_lport |
110 | * @shost: ptr to the parent scsi host | 110 | * @shost: ptr to the parent scsi host |
111 | * | 111 | * |
112 | * Returns: 0 for success | 112 | * Returns: 0 for success |
113 | */ | 113 | */ |
114 | static int fcoe_sw_lport_config(struct fc_lport *lp) | 114 | static int fcoe_sw_lport_config(struct fc_lport *lp) |
115 | { | 115 | { |
116 | int i = 0; | 116 | int i = 0; |
117 | 117 | ||
118 | lp->link_up = 0; | 118 | lp->link_up = 0; |
119 | lp->qfull = 0; | 119 | lp->qfull = 0; |
120 | lp->max_retry_count = 3; | 120 | lp->max_retry_count = 3; |
121 | lp->e_d_tov = 2 * 1000; /* FC-FS default */ | 121 | lp->e_d_tov = 2 * 1000; /* FC-FS default */ |
122 | lp->r_a_tov = 2 * 2 * 1000; | 122 | lp->r_a_tov = 2 * 2 * 1000; |
123 | lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | | 123 | lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | |
124 | FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); | 124 | FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); |
125 | 125 | ||
126 | /* | 126 | /* |
127 | * allocate per cpu stats block | 127 | * allocate per cpu stats block |
128 | */ | 128 | */ |
129 | for_each_online_cpu(i) | 129 | for_each_online_cpu(i) |
130 | lp->dev_stats[i] = kzalloc(sizeof(struct fcoe_dev_stats), | 130 | lp->dev_stats[i] = kzalloc(sizeof(struct fcoe_dev_stats), |
131 | GFP_KERNEL); | 131 | GFP_KERNEL); |
132 | 132 | ||
133 | /* lport fc_lport related configuration */ | 133 | /* lport fc_lport related configuration */ |
134 | fc_lport_config(lp); | 134 | fc_lport_config(lp); |
135 | 135 | ||
136 | /* offload related configuration */ | 136 | /* offload related configuration */ |
137 | lp->crc_offload = 0; | 137 | lp->crc_offload = 0; |
138 | lp->seq_offload = 0; | 138 | lp->seq_offload = 0; |
139 | lp->lro_enabled = 0; | 139 | lp->lro_enabled = 0; |
140 | lp->lro_xid = 0; | 140 | lp->lro_xid = 0; |
141 | lp->lso_max = 0; | 141 | lp->lso_max = 0; |
142 | 142 | ||
143 | return 0; | 143 | return 0; |
144 | } | 144 | } |
145 | 145 | ||
146 | /** | 146 | /** |
147 | * fcoe_sw_netdev_config() - Set up netdev for SW FCoE | 147 | * fcoe_sw_netdev_config() - Set up netdev for SW FCoE |
148 | * @lp : ptr to the fc_lport | 148 | * @lp : ptr to the fc_lport |
149 | * @netdev : ptr to the associated netdevice struct | 149 | * @netdev : ptr to the associated netdevice struct |
150 | * | 150 | * |
151 | * Must be called after fcoe_sw_lport_config() as it will use lport mutex | 151 | * Must be called after fcoe_sw_lport_config() as it will use lport mutex |
152 | * | 152 | * |
153 | * Returns : 0 for success | 153 | * Returns : 0 for success |
154 | */ | 154 | */ |
155 | static int fcoe_sw_netdev_config(struct fc_lport *lp, struct net_device *netdev) | 155 | static int fcoe_sw_netdev_config(struct fc_lport *lp, struct net_device *netdev) |
156 | { | 156 | { |
157 | u32 mfs; | 157 | u32 mfs; |
158 | u64 wwnn, wwpn; | 158 | u64 wwnn, wwpn; |
159 | struct fcoe_softc *fc; | 159 | struct fcoe_softc *fc; |
160 | u8 flogi_maddr[ETH_ALEN]; | 160 | u8 flogi_maddr[ETH_ALEN]; |
161 | 161 | ||
162 | /* Setup lport private data to point to fcoe softc */ | 162 | /* Setup lport private data to point to fcoe softc */ |
163 | fc = lport_priv(lp); | 163 | fc = lport_priv(lp); |
164 | fc->lp = lp; | 164 | fc->lp = lp; |
165 | fc->real_dev = netdev; | 165 | fc->real_dev = netdev; |
166 | fc->phys_dev = netdev; | 166 | fc->phys_dev = netdev; |
167 | 167 | ||
168 | /* Require support for get_pauseparam ethtool op. */ | 168 | /* Require support for get_pauseparam ethtool op. */ |
169 | if (netdev->priv_flags & IFF_802_1Q_VLAN) | 169 | if (netdev->priv_flags & IFF_802_1Q_VLAN) |
170 | fc->phys_dev = vlan_dev_real_dev(netdev); | 170 | fc->phys_dev = vlan_dev_real_dev(netdev); |
171 | 171 | ||
172 | /* Do not support for bonding device */ | 172 | /* Do not support for bonding device */ |
173 | if ((fc->real_dev->priv_flags & IFF_MASTER_ALB) || | 173 | if ((fc->real_dev->priv_flags & IFF_MASTER_ALB) || |
174 | (fc->real_dev->priv_flags & IFF_SLAVE_INACTIVE) || | 174 | (fc->real_dev->priv_flags & IFF_SLAVE_INACTIVE) || |
175 | (fc->real_dev->priv_flags & IFF_MASTER_8023AD)) { | 175 | (fc->real_dev->priv_flags & IFF_MASTER_8023AD)) { |
176 | return -EOPNOTSUPP; | 176 | return -EOPNOTSUPP; |
177 | } | 177 | } |
178 | 178 | ||
179 | /* | 179 | /* |
180 | * Determine max frame size based on underlying device and optional | 180 | * Determine max frame size based on underlying device and optional |
181 | * user-configured limit. If the MFS is too low, fcoe_link_ok() | 181 | * user-configured limit. If the MFS is too low, fcoe_link_ok() |
182 | * will return 0, so do this first. | 182 | * will return 0, so do this first. |
183 | */ | 183 | */ |
184 | mfs = fc->real_dev->mtu - (sizeof(struct fcoe_hdr) + | 184 | mfs = fc->real_dev->mtu - (sizeof(struct fcoe_hdr) + |
185 | sizeof(struct fcoe_crc_eof)); | 185 | sizeof(struct fcoe_crc_eof)); |
186 | if (fc_set_mfs(lp, mfs)) | 186 | if (fc_set_mfs(lp, mfs)) |
187 | return -EINVAL; | 187 | return -EINVAL; |
188 | 188 | ||
189 | if (!fcoe_link_ok(lp)) | 189 | if (!fcoe_link_ok(lp)) |
190 | lp->link_up = 1; | 190 | lp->link_up = 1; |
191 | 191 | ||
192 | /* offload features support */ | 192 | /* offload features support */ |
193 | if (fc->real_dev->features & NETIF_F_SG) | 193 | if (fc->real_dev->features & NETIF_F_SG) |
194 | lp->sg_supp = 1; | 194 | lp->sg_supp = 1; |
195 | 195 | ||
196 | #ifdef NETIF_F_FCOE_CRC | 196 | #ifdef NETIF_F_FCOE_CRC |
197 | if (netdev->features & NETIF_F_FCOE_CRC) { | 197 | if (netdev->features & NETIF_F_FCOE_CRC) { |
198 | lp->crc_offload = 1; | 198 | lp->crc_offload = 1; |
199 | printk(KERN_DEBUG "fcoe:%s supports FCCRC offload\n", | 199 | printk(KERN_DEBUG "fcoe:%s supports FCCRC offload\n", |
200 | netdev->name); | 200 | netdev->name); |
201 | } | 201 | } |
202 | #endif | 202 | #endif |
203 | #ifdef NETIF_F_FSO | 203 | #ifdef NETIF_F_FSO |
204 | if (netdev->features & NETIF_F_FSO) { | 204 | if (netdev->features & NETIF_F_FSO) { |
205 | lp->seq_offload = 1; | 205 | lp->seq_offload = 1; |
206 | lp->lso_max = netdev->gso_max_size; | 206 | lp->lso_max = netdev->gso_max_size; |
207 | printk(KERN_DEBUG "fcoe:%s supports LSO for max len 0x%x\n", | 207 | printk(KERN_DEBUG "fcoe:%s supports LSO for max len 0x%x\n", |
208 | netdev->name, lp->lso_max); | 208 | netdev->name, lp->lso_max); |
209 | } | 209 | } |
210 | #endif | 210 | #endif |
211 | if (netdev->fcoe_ddp_xid) { | 211 | if (netdev->fcoe_ddp_xid) { |
212 | lp->lro_enabled = 1; | 212 | lp->lro_enabled = 1; |
213 | lp->lro_xid = netdev->fcoe_ddp_xid; | 213 | lp->lro_xid = netdev->fcoe_ddp_xid; |
214 | printk(KERN_DEBUG "fcoe:%s supports LRO for max xid 0x%x\n", | 214 | printk(KERN_DEBUG "fcoe:%s supports LRO for max xid 0x%x\n", |
215 | netdev->name, lp->lro_xid); | 215 | netdev->name, lp->lro_xid); |
216 | } | 216 | } |
217 | skb_queue_head_init(&fc->fcoe_pending_queue); | 217 | skb_queue_head_init(&fc->fcoe_pending_queue); |
218 | fc->fcoe_pending_queue_active = 0; | 218 | fc->fcoe_pending_queue_active = 0; |
219 | 219 | ||
220 | /* setup Source Mac Address */ | 220 | /* setup Source Mac Address */ |
221 | memcpy(fc->ctl_src_addr, fc->real_dev->dev_addr, | 221 | memcpy(fc->ctl_src_addr, fc->real_dev->dev_addr, |
222 | fc->real_dev->addr_len); | 222 | fc->real_dev->addr_len); |
223 | 223 | ||
224 | wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0); | 224 | wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0); |
225 | fc_set_wwnn(lp, wwnn); | 225 | fc_set_wwnn(lp, wwnn); |
226 | /* XXX - 3rd arg needs to be vlan id */ | 226 | /* XXX - 3rd arg needs to be vlan id */ |
227 | wwpn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 2, 0); | 227 | wwpn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 2, 0); |
228 | fc_set_wwpn(lp, wwpn); | 228 | fc_set_wwpn(lp, wwpn); |
229 | 229 | ||
230 | /* | 230 | /* |
231 | * Add FCoE MAC address as second unicast MAC address | 231 | * Add FCoE MAC address as second unicast MAC address |
232 | * or enter promiscuous mode if not capable of listening | 232 | * or enter promiscuous mode if not capable of listening |
233 | * for multiple unicast MACs. | 233 | * for multiple unicast MACs. |
234 | */ | 234 | */ |
235 | rtnl_lock(); | 235 | rtnl_lock(); |
236 | memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); | 236 | memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); |
237 | dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN); | 237 | dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN); |
238 | rtnl_unlock(); | 238 | rtnl_unlock(); |
239 | 239 | ||
240 | /* | 240 | /* |
241 | * setup the receive function from ethernet driver | 241 | * setup the receive function from ethernet driver |
242 | * on the ethertype for the given device | 242 | * on the ethertype for the given device |
243 | */ | 243 | */ |
244 | fc->fcoe_packet_type.func = fcoe_rcv; | 244 | fc->fcoe_packet_type.func = fcoe_rcv; |
245 | fc->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); | 245 | fc->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); |
246 | fc->fcoe_packet_type.dev = fc->real_dev; | 246 | fc->fcoe_packet_type.dev = fc->real_dev; |
247 | dev_add_pack(&fc->fcoe_packet_type); | 247 | dev_add_pack(&fc->fcoe_packet_type); |
248 | 248 | ||
249 | return 0; | 249 | return 0; |
250 | } | 250 | } |
251 | 251 | ||
252 | /** | 252 | /** |
253 | * fcoe_sw_shost_config() - Sets up fc_lport->host | 253 | * fcoe_sw_shost_config() - Sets up fc_lport->host |
254 | * @lp : ptr to the fc_lport | 254 | * @lp : ptr to the fc_lport |
255 | * @shost : ptr to the associated scsi host | 255 | * @shost : ptr to the associated scsi host |
256 | * @dev : device associated to scsi host | 256 | * @dev : device associated to scsi host |
257 | * | 257 | * |
258 | * Must be called after fcoe_sw_lport_config() and fcoe_sw_netdev_config() | 258 | * Must be called after fcoe_sw_lport_config() and fcoe_sw_netdev_config() |
259 | * | 259 | * |
260 | * Returns : 0 for success | 260 | * Returns : 0 for success |
261 | */ | 261 | */ |
262 | static int fcoe_sw_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, | 262 | static int fcoe_sw_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, |
263 | struct device *dev) | 263 | struct device *dev) |
264 | { | 264 | { |
265 | int rc = 0; | 265 | int rc = 0; |
266 | 266 | ||
267 | /* lport scsi host config */ | 267 | /* lport scsi host config */ |
268 | lp->host = shost; | 268 | lp->host = shost; |
269 | 269 | ||
270 | lp->host->max_lun = FCOE_MAX_LUN; | 270 | lp->host->max_lun = FCOE_MAX_LUN; |
271 | lp->host->max_id = FCOE_MAX_FCP_TARGET; | 271 | lp->host->max_id = FCOE_MAX_FCP_TARGET; |
272 | lp->host->max_channel = 0; | 272 | lp->host->max_channel = 0; |
273 | lp->host->transportt = scsi_transport_fcoe_sw; | 273 | lp->host->transportt = scsi_transport_fcoe_sw; |
274 | 274 | ||
275 | /* add the new host to the SCSI-ml */ | 275 | /* add the new host to the SCSI-ml */ |
276 | rc = scsi_add_host(lp->host, dev); | 276 | rc = scsi_add_host(lp->host, dev); |
277 | if (rc) { | 277 | if (rc) { |
278 | FC_DBG("fcoe_sw_shost_config:error on scsi_add_host\n"); | 278 | FC_DBG("fcoe_sw_shost_config:error on scsi_add_host\n"); |
279 | return rc; | 279 | return rc; |
280 | } | 280 | } |
281 | sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s", | 281 | sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s", |
282 | FCOE_SW_NAME, FCOE_SW_VERSION, | 282 | FCOE_SW_NAME, FCOE_SW_VERSION, |
283 | fcoe_netdev(lp)->name); | 283 | fcoe_netdev(lp)->name); |
284 | 284 | ||
285 | return 0; | 285 | return 0; |
286 | } | 286 | } |
287 | 287 | ||
288 | /** | 288 | /** |
289 | * fcoe_sw_em_config() - allocates em for this lport | 289 | * fcoe_sw_em_config() - allocates em for this lport |
290 | * @lp: the port that em is to allocated for | 290 | * @lp: the port that em is to allocated for |
291 | * | 291 | * |
292 | * Returns : 0 on success | 292 | * Returns : 0 on success |
293 | */ | 293 | */ |
294 | static inline int fcoe_sw_em_config(struct fc_lport *lp) | 294 | static inline int fcoe_sw_em_config(struct fc_lport *lp) |
295 | { | 295 | { |
296 | BUG_ON(lp->emp); | 296 | BUG_ON(lp->emp); |
297 | 297 | ||
298 | lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, | 298 | lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, |
299 | FCOE_MIN_XID, FCOE_MAX_XID); | 299 | FCOE_MIN_XID, FCOE_MAX_XID); |
300 | if (!lp->emp) | 300 | if (!lp->emp) |
301 | return -ENOMEM; | 301 | return -ENOMEM; |
302 | 302 | ||
303 | return 0; | 303 | return 0; |
304 | } | 304 | } |
305 | 305 | ||
306 | /** | 306 | /** |
307 | * fcoe_sw_destroy() - FCoE software HBA tear-down function | 307 | * fcoe_sw_destroy() - FCoE software HBA tear-down function |
308 | * @netdev: ptr to the associated net_device | 308 | * @netdev: ptr to the associated net_device |
309 | * | 309 | * |
310 | * Returns: 0 if link is OK for use by FCoE. | 310 | * Returns: 0 if link is OK for use by FCoE. |
311 | */ | 311 | */ |
312 | static int fcoe_sw_destroy(struct net_device *netdev) | 312 | static int fcoe_sw_destroy(struct net_device *netdev) |
313 | { | 313 | { |
314 | int cpu; | 314 | int cpu; |
315 | struct fc_lport *lp = NULL; | 315 | struct fc_lport *lp = NULL; |
316 | struct fcoe_softc *fc; | 316 | struct fcoe_softc *fc; |
317 | u8 flogi_maddr[ETH_ALEN]; | 317 | u8 flogi_maddr[ETH_ALEN]; |
318 | 318 | ||
319 | BUG_ON(!netdev); | 319 | BUG_ON(!netdev); |
320 | 320 | ||
321 | printk(KERN_DEBUG "fcoe_sw_destroy:interface on %s\n", | 321 | printk(KERN_DEBUG "fcoe_sw_destroy:interface on %s\n", |
322 | netdev->name); | 322 | netdev->name); |
323 | 323 | ||
324 | lp = fcoe_hostlist_lookup(netdev); | 324 | lp = fcoe_hostlist_lookup(netdev); |
325 | if (!lp) | 325 | if (!lp) |
326 | return -ENODEV; | 326 | return -ENODEV; |
327 | 327 | ||
328 | fc = lport_priv(lp); | 328 | fc = lport_priv(lp); |
329 | 329 | ||
330 | /* Logout of the fabric */ | 330 | /* Logout of the fabric */ |
331 | fc_fabric_logoff(lp); | 331 | fc_fabric_logoff(lp); |
332 | 332 | ||
333 | /* Remove the instance from fcoe's list */ | 333 | /* Remove the instance from fcoe's list */ |
334 | fcoe_hostlist_remove(lp); | 334 | fcoe_hostlist_remove(lp); |
335 | 335 | ||
336 | /* Don't listen for Ethernet packets anymore */ | 336 | /* Don't listen for Ethernet packets anymore */ |
337 | dev_remove_pack(&fc->fcoe_packet_type); | 337 | dev_remove_pack(&fc->fcoe_packet_type); |
338 | 338 | ||
339 | /* Cleanup the fc_lport */ | 339 | /* Cleanup the fc_lport */ |
340 | fc_lport_destroy(lp); | 340 | fc_lport_destroy(lp); |
341 | fc_fcp_destroy(lp); | 341 | fc_fcp_destroy(lp); |
342 | 342 | ||
343 | /* Detach from the scsi-ml */ | 343 | /* Detach from the scsi-ml */ |
344 | fc_remove_host(lp->host); | 344 | fc_remove_host(lp->host); |
345 | scsi_remove_host(lp->host); | 345 | scsi_remove_host(lp->host); |
346 | 346 | ||
347 | /* There are no more rports or I/O, free the EM */ | 347 | /* There are no more rports or I/O, free the EM */ |
348 | if (lp->emp) | 348 | if (lp->emp) |
349 | fc_exch_mgr_free(lp->emp); | 349 | fc_exch_mgr_free(lp->emp); |
350 | 350 | ||
351 | /* Delete secondary MAC addresses */ | 351 | /* Delete secondary MAC addresses */ |
352 | rtnl_lock(); | 352 | rtnl_lock(); |
353 | memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); | 353 | memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); |
354 | dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); | 354 | dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); |
355 | if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) | 355 | if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) |
356 | dev_unicast_delete(fc->real_dev, fc->data_src_addr, ETH_ALEN); | 356 | dev_unicast_delete(fc->real_dev, fc->data_src_addr, ETH_ALEN); |
357 | rtnl_unlock(); | 357 | rtnl_unlock(); |
358 | 358 | ||
359 | /* Free the per-CPU revieve threads */ | 359 | /* Free the per-CPU revieve threads */ |
360 | fcoe_percpu_clean(lp); | 360 | fcoe_percpu_clean(lp); |
361 | 361 | ||
362 | /* Free existing skbs */ | 362 | /* Free existing skbs */ |
363 | fcoe_clean_pending_queue(lp); | 363 | fcoe_clean_pending_queue(lp); |
364 | 364 | ||
365 | /* Free memory used by statistical counters */ | 365 | /* Free memory used by statistical counters */ |
366 | for_each_online_cpu(cpu) | 366 | for_each_online_cpu(cpu) |
367 | kfree(lp->dev_stats[cpu]); | 367 | kfree(lp->dev_stats[cpu]); |
368 | 368 | ||
369 | /* Release the net_device and Scsi_Host */ | 369 | /* Release the net_device and Scsi_Host */ |
370 | dev_put(fc->real_dev); | 370 | dev_put(fc->real_dev); |
371 | scsi_host_put(lp->host); | 371 | scsi_host_put(lp->host); |
372 | 372 | ||
373 | return 0; | 373 | return 0; |
374 | } | 374 | } |
375 | 375 | ||
376 | /* | ||
377 | * fcoe_sw_ddp_setup - calls LLD's ddp_setup through net_device | ||
378 | * @lp: the corresponding fc_lport | ||
379 | * @xid: the exchange id for this ddp transfer | ||
380 | * @sgl: the scatterlist describing this transfer | ||
381 | * @sgc: number of sg items | ||
382 | * | ||
383 | * Returns : 0 no ddp | ||
384 | */ | ||
385 | static int fcoe_sw_ddp_setup(struct fc_lport *lp, u16 xid, | ||
386 | struct scatterlist *sgl, unsigned int sgc) | ||
387 | { | ||
388 | struct net_device *n = fcoe_netdev(lp); | ||
389 | |||
390 | if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_setup) | ||
391 | return n->netdev_ops->ndo_fcoe_ddp_setup(n, xid, sgl, sgc); | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | /* | ||
397 | * fcoe_sw_ddp_done - calls LLD's ddp_done through net_device | ||
398 | * @lp: the corresponding fc_lport | ||
399 | * @xid: the exchange id for this ddp transfer | ||
400 | * | ||
401 | * Returns : the length of data that have been completed by ddp | ||
402 | */ | ||
403 | static int fcoe_sw_ddp_done(struct fc_lport *lp, u16 xid) | ||
404 | { | ||
405 | struct net_device *n = fcoe_netdev(lp); | ||
406 | |||
407 | if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_done) | ||
408 | return n->netdev_ops->ndo_fcoe_ddp_done(n, xid); | ||
409 | return 0; | ||
410 | } | ||
411 | |||
376 | static struct libfc_function_template fcoe_sw_libfc_fcn_templ = { | 412 | static struct libfc_function_template fcoe_sw_libfc_fcn_templ = { |
377 | .frame_send = fcoe_xmit, | 413 | .frame_send = fcoe_xmit, |
414 | .ddp_setup = fcoe_sw_ddp_setup, | ||
415 | .ddp_done = fcoe_sw_ddp_done, | ||
378 | }; | 416 | }; |
379 | 417 | ||
380 | /** | 418 | /** |
381 | * fcoe_sw_create() - this function creates the fcoe interface | 419 | * fcoe_sw_create() - this function creates the fcoe interface |
382 | * @netdev: pointer the associated netdevice | 420 | * @netdev: pointer the associated netdevice |
383 | * | 421 | * |
384 | * Creates fc_lport struct and scsi_host for lport, configures lport | 422 | * Creates fc_lport struct and scsi_host for lport, configures lport |
385 | * and starts fabric login. | 423 | * and starts fabric login. |
386 | * | 424 | * |
387 | * Returns : 0 on success | 425 | * Returns : 0 on success |
388 | */ | 426 | */ |
389 | static int fcoe_sw_create(struct net_device *netdev) | 427 | static int fcoe_sw_create(struct net_device *netdev) |
390 | { | 428 | { |
391 | int rc; | 429 | int rc; |
392 | struct fc_lport *lp = NULL; | 430 | struct fc_lport *lp = NULL; |
393 | struct fcoe_softc *fc; | 431 | struct fcoe_softc *fc; |
394 | struct Scsi_Host *shost; | 432 | struct Scsi_Host *shost; |
395 | 433 | ||
396 | BUG_ON(!netdev); | 434 | BUG_ON(!netdev); |
397 | 435 | ||
398 | printk(KERN_DEBUG "fcoe_sw_create:interface on %s\n", | 436 | printk(KERN_DEBUG "fcoe_sw_create:interface on %s\n", |
399 | netdev->name); | 437 | netdev->name); |
400 | 438 | ||
401 | lp = fcoe_hostlist_lookup(netdev); | 439 | lp = fcoe_hostlist_lookup(netdev); |
402 | if (lp) | 440 | if (lp) |
403 | return -EEXIST; | 441 | return -EEXIST; |
404 | 442 | ||
405 | shost = fcoe_host_alloc(&fcoe_sw_shost_template, | 443 | shost = fcoe_host_alloc(&fcoe_sw_shost_template, |
406 | sizeof(struct fcoe_softc)); | 444 | sizeof(struct fcoe_softc)); |
407 | if (!shost) { | 445 | if (!shost) { |
408 | FC_DBG("Could not allocate host structure\n"); | 446 | FC_DBG("Could not allocate host structure\n"); |
409 | return -ENOMEM; | 447 | return -ENOMEM; |
410 | } | 448 | } |
411 | lp = shost_priv(shost); | 449 | lp = shost_priv(shost); |
412 | fc = lport_priv(lp); | 450 | fc = lport_priv(lp); |
413 | 451 | ||
414 | /* configure fc_lport, e.g., em */ | 452 | /* configure fc_lport, e.g., em */ |
415 | rc = fcoe_sw_lport_config(lp); | 453 | rc = fcoe_sw_lport_config(lp); |
416 | if (rc) { | 454 | if (rc) { |
417 | FC_DBG("Could not configure lport\n"); | 455 | FC_DBG("Could not configure lport\n"); |
418 | goto out_host_put; | 456 | goto out_host_put; |
419 | } | 457 | } |
420 | 458 | ||
421 | /* configure lport network properties */ | 459 | /* configure lport network properties */ |
422 | rc = fcoe_sw_netdev_config(lp, netdev); | 460 | rc = fcoe_sw_netdev_config(lp, netdev); |
423 | if (rc) { | 461 | if (rc) { |
424 | FC_DBG("Could not configure netdev for lport\n"); | 462 | FC_DBG("Could not configure netdev for lport\n"); |
425 | goto out_host_put; | 463 | goto out_host_put; |
426 | } | 464 | } |
427 | 465 | ||
428 | /* configure lport scsi host properties */ | 466 | /* configure lport scsi host properties */ |
429 | rc = fcoe_sw_shost_config(lp, shost, &netdev->dev); | 467 | rc = fcoe_sw_shost_config(lp, shost, &netdev->dev); |
430 | if (rc) { | 468 | if (rc) { |
431 | FC_DBG("Could not configure shost for lport\n"); | 469 | FC_DBG("Could not configure shost for lport\n"); |
432 | goto out_host_put; | 470 | goto out_host_put; |
433 | } | 471 | } |
434 | 472 | ||
435 | /* lport exch manager allocation */ | 473 | /* lport exch manager allocation */ |
436 | rc = fcoe_sw_em_config(lp); | 474 | rc = fcoe_sw_em_config(lp); |
437 | if (rc) { | 475 | if (rc) { |
438 | FC_DBG("Could not configure em for lport\n"); | 476 | FC_DBG("Could not configure em for lport\n"); |
439 | goto out_host_put; | 477 | goto out_host_put; |
440 | } | 478 | } |
441 | 479 | ||
442 | /* Initialize the library */ | 480 | /* Initialize the library */ |
443 | rc = fcoe_libfc_config(lp, &fcoe_sw_libfc_fcn_templ); | 481 | rc = fcoe_libfc_config(lp, &fcoe_sw_libfc_fcn_templ); |
444 | if (rc) { | 482 | if (rc) { |
445 | FC_DBG("Could not configure libfc for lport!\n"); | 483 | FC_DBG("Could not configure libfc for lport!\n"); |
446 | goto out_lp_destroy; | 484 | goto out_lp_destroy; |
447 | } | 485 | } |
448 | 486 | ||
449 | /* add to lports list */ | 487 | /* add to lports list */ |
450 | fcoe_hostlist_add(lp); | 488 | fcoe_hostlist_add(lp); |
451 | 489 | ||
452 | lp->boot_time = jiffies; | 490 | lp->boot_time = jiffies; |
453 | 491 | ||
454 | fc_fabric_login(lp); | 492 | fc_fabric_login(lp); |
455 | 493 | ||
456 | dev_hold(netdev); | 494 | dev_hold(netdev); |
457 | 495 | ||
458 | return rc; | 496 | return rc; |
459 | 497 | ||
460 | out_lp_destroy: | 498 | out_lp_destroy: |
461 | fc_exch_mgr_free(lp->emp); /* Free the EM */ | 499 | fc_exch_mgr_free(lp->emp); /* Free the EM */ |
462 | out_host_put: | 500 | out_host_put: |
463 | scsi_host_put(lp->host); | 501 | scsi_host_put(lp->host); |
464 | return rc; | 502 | return rc; |
465 | } | 503 | } |
466 | 504 | ||
467 | /** | 505 | /** |
468 | * fcoe_sw_match() - The FCoE SW transport match function | 506 | * fcoe_sw_match() - The FCoE SW transport match function |
469 | * | 507 | * |
470 | * Returns : false always | 508 | * Returns : false always |
471 | */ | 509 | */ |
472 | static bool fcoe_sw_match(struct net_device *netdev) | 510 | static bool fcoe_sw_match(struct net_device *netdev) |
473 | { | 511 | { |
474 | /* FIXME - for sw transport, always return false */ | 512 | /* FIXME - for sw transport, always return false */ |
475 | return false; | 513 | return false; |
476 | } | 514 | } |
477 | 515 | ||
478 | /* the sw hba fcoe transport */ | 516 | /* the sw hba fcoe transport */ |
479 | struct fcoe_transport fcoe_sw_transport = { | 517 | struct fcoe_transport fcoe_sw_transport = { |
480 | .name = "fcoesw", | 518 | .name = "fcoesw", |
481 | .create = fcoe_sw_create, | 519 | .create = fcoe_sw_create, |
482 | .destroy = fcoe_sw_destroy, | 520 | .destroy = fcoe_sw_destroy, |
483 | .match = fcoe_sw_match, | 521 | .match = fcoe_sw_match, |
484 | .vendor = 0x0, | 522 | .vendor = 0x0, |
485 | .device = 0xffff, | 523 | .device = 0xffff, |
486 | }; | 524 | }; |
487 | 525 | ||
488 | /** | 526 | /** |
489 | * fcoe_sw_init() - Registers fcoe_sw_transport | 527 | * fcoe_sw_init() - Registers fcoe_sw_transport |
490 | * | 528 | * |
491 | * Returns : 0 on success | 529 | * Returns : 0 on success |
492 | */ | 530 | */ |
493 | int __init fcoe_sw_init(void) | 531 | int __init fcoe_sw_init(void) |
494 | { | 532 | { |
495 | /* attach to scsi transport */ | 533 | /* attach to scsi transport */ |
496 | scsi_transport_fcoe_sw = | 534 | scsi_transport_fcoe_sw = |
497 | fc_attach_transport(&fcoe_sw_transport_function); | 535 | fc_attach_transport(&fcoe_sw_transport_function); |
498 | 536 | ||
499 | if (!scsi_transport_fcoe_sw) { | 537 | if (!scsi_transport_fcoe_sw) { |
500 | printk(KERN_ERR "fcoe_sw_init:fc_attach_transport() failed\n"); | 538 | printk(KERN_ERR "fcoe_sw_init:fc_attach_transport() failed\n"); |
501 | return -ENODEV; | 539 | return -ENODEV; |
502 | } | 540 | } |
503 | 541 | ||
504 | mutex_init(&fcoe_sw_transport.devlock); | 542 | mutex_init(&fcoe_sw_transport.devlock); |
505 | INIT_LIST_HEAD(&fcoe_sw_transport.devlist); | 543 | INIT_LIST_HEAD(&fcoe_sw_transport.devlist); |
506 | 544 | ||
507 | /* register sw transport */ | 545 | /* register sw transport */ |
508 | fcoe_transport_register(&fcoe_sw_transport); | 546 | fcoe_transport_register(&fcoe_sw_transport); |
509 | return 0; | 547 | return 0; |
510 | } | 548 | } |
511 | 549 | ||
512 | /** | 550 | /** |
513 | * fcoe_sw_exit() - Unregisters fcoe_sw_transport | 551 | * fcoe_sw_exit() - Unregisters fcoe_sw_transport |
514 | * | 552 | * |
515 | * Returns : 0 on success | 553 | * Returns : 0 on success |
516 | */ | 554 | */ |
517 | int __exit fcoe_sw_exit(void) | 555 | int __exit fcoe_sw_exit(void) |
518 | { | 556 | { |
519 | /* dettach the transport */ | 557 | /* dettach the transport */ |
520 | fc_release_transport(scsi_transport_fcoe_sw); | 558 | fc_release_transport(scsi_transport_fcoe_sw); |
521 | fcoe_transport_unregister(&fcoe_sw_transport); | 559 | fcoe_transport_unregister(&fcoe_sw_transport); |
522 | return 0; | 560 | return 0; |
523 | } | 561 | } |
524 | 562 |