aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/scsi/scsi_fc_transport.txt450
-rw-r--r--drivers/scsi/scsi_transport_fc.c805
-rw-r--r--include/scsi/scsi_transport_fc.h173
3 files changed, 1399 insertions, 29 deletions
diff --git a/Documentation/scsi/scsi_fc_transport.txt b/Documentation/scsi/scsi_fc_transport.txt
new file mode 100644
index 000000000000..ab057afc757f
--- /dev/null
+++ b/Documentation/scsi/scsi_fc_transport.txt
@@ -0,0 +1,450 @@
1 SCSI FC Tansport
2 =============================================
3
4Date: 4/12/2007
5Kernel Revisions for features:
6 rports : <<TBS>>
7 vports : 2.6.22 (? TBD)
8
9
10Introduction
11============
12This file documents the features and components of the SCSI FC Transport.
13It also provides documents the API between the transport and FC LLDDs.
14The FC transport can be found at:
15 drivers/scsi/scsi_transport_fc.c
16 include/scsi/scsi_transport_fc.h
17 include/scsi/scsi_netlink_fc.h
18
19This file is found at Documentation/scsi/scsi_fc_transport.txt
20
21
22FC Remote Ports (rports)
23========================================================================
24<< To Be Supplied >>
25
26
27FC Virtual Ports (vports)
28========================================================================
29
30Overview:
31-------------------------------
32
33 New FC standards have defined mechanisms which allows for a single physical
34 port to appear on as multiple communication ports. Using the N_Port Id
35 Virtualization (NPIV) mechanism, a point-to-point connection to a Fabric
36 can be assigned more than 1 N_Port_ID. Each N_Port_ID appears as a
37 separate port to other endpoints on the fabric, even though it shares one
38 physical link to the switch for communication. Each N_Port_ID can have a
39 unique view of the fabric based on fabric zoning and array lun-masking
40 (just like a normal non-NPIV adapter). Using the Virtual Fabric (VF)
41 mechanism, adding a fabric header to each frame allows the port to
42 interact with the Fabric Port to join multiple fabrics. The port will
43 obtain an N_Port_ID on each fabric it joins. Each fabric will have its
44 own unique view of endpoints and configuration parameters. NPIV may be
45 used together with VF so that the port can obtain multiple N_Port_IDs
46 on each virtual fabric.
47
48 The FC transport is now recognizing a new object - a vport. A vport is
49 an entity that has a world-wide unique World Wide Port Name (wwpn) and
50 World Wide Node Name (wwnn). The transport also allows for the FC4's to
51 be specified for the vport, with FCP_Initiator being the primary role
52 expected. Once instantiated by one of the above methods, it will have a
53 distinct N_Port_ID and view of fabric endpoints and storage entities.
54 The fc_host associated with the physical adapter will export the ability
55 to create vports. The transport will create the vport object within the
56 Linux device tree, and instruct the fc_host's driver to instantiate the
57 virtual port. Typically, the driver will create a new scsi_host instance
58 on the vport, resulting in a unique <H,C,T,L> namespace for the vport.
59 Thus, whether a FC port is based on a physical port or on a virtual port,
60 each will appear as a unique scsi_host with its own target and lun space.
61
62 Note: At this time, the transport is written to create only NPIV-based
63 vports. However, consideration was given to VF-based vports and it
64 should be a minor change to add support if needed. The remaining
65 discussion will concentrate on NPIV.
66
67 Note: World Wide Name assignment (and uniqueness guarantees) are left
68 up to an administrative entity controling the vport. For example,
69 if vports are to be associated with virtual machines, a XEN mgmt
70 utility would be responsible for creating wwpn/wwnn's for the vport,
71 using it's own naming authority and OUI. (Note: it already does this
72 for virtual MAC addresses).
73
74
75Device Trees and Vport Objects:
76-------------------------------
77
78 Today, the device tree typically contains the scsi_host object,
79 with rports and scsi target objects underneath it. Currently the FC
80 transport creates the vport object and places it under the scsi_host
81 object corresponding to the physical adapter. The LLDD will allocate
82 a new scsi_host for the vport and link it's object under the vport.
83 The remainder of the tree under the vports scsi_host is the same
84 as the non-NPIV case. The transport is written currently to easily
85 allow the parent of the vport to be something other than the scsi_host.
86 This could be used in the future to link the object onto a vm-specific
87 device tree. If the vport's parent is not the physical port's scsi_host,
88 a symbolic link to the vport object will be placed in the physical
89 port's scsi_host.
90
91 Here's what to expect in the device tree :
92 The typical Physical Port's Scsi_Host:
93 /sys/devices/.../host17/
94 and it has the typical decendent tree:
95 /sys/devices/.../host17/rport-17:0-0/target17:0:0/17:0:0:0:
96 and then the vport is created on the Physical Port:
97 /sys/devices/.../host17/vport-17:0-0
98 and the vport's Scsi_Host is then created:
99 /sys/devices/.../host17/vport-17:0-0/host18
100 and then the rest of the tree progresses, such as:
101 /sys/devices/.../host17/vport-17:0-0/host18/rport-18:0-0/target18:0:0/18:0:0:0:
102
103 Here's what to expect in the sysfs tree :
104 scsi_hosts:
105 /sys/class/scsi_host/host17 physical port's scsi_host
106 /sys/class/scsi_host/host18 vport's scsi_host
107 fc_hosts:
108 /sys/class/fc_host/host17 physical port's fc_host
109 /sys/class/fc_host/host18 vport's fc_host
110 fc_vports:
111 /sys/class/fc_vports/vport-17:0-0 the vport's fc_vport
112 fc_rports:
113 /sys/class/fc_remote_ports/rport-17:0-0 rport on the physical port
114 /sys/class/fc_remote_ports/rport-18:0-0 rport on the vport
115
116
117Vport Attributes:
118-------------------------------
119
120 The new fc_vport class object has the following attributes
121
122 node_name: Read_Only
123 The WWNN of the vport
124
125 port_name: Read_Only
126 The WWPN of the vport
127
128 roles: Read_Only
129 Indicates the FC4 roles enabled on the vport.
130
131 symbolic_name: Read_Write
132 A string, appended to the driver's symbolic port name string, which
133 is registered with the switch to identify the vport. For example,
134 a hypervisor could set this string to "Xen Domain 2 VM 5 Vport 2",
135 and this set of identifiers can be seen on switch management screens
136 to identify the port.
137
138 vport_delete: Write_Only
139 When written with a "1", will tear down the vport.
140
141 vport_disable: Write_Only
142 When written with a "1", will transition the vport to a disabled.
143 state. The vport will still be instantiated with the Linux kernel,
144 but it will not be active on the FC link.
145 When written with a "0", will enable the vport.
146
147 vport_last_state: Read_Only
148 Indicates the previous state of the vport. See the section below on
149 "Vport States".
150
151 vport_state: Read_Only
152 Indicates the state of the vport. See the section below on
153 "Vport States".
154
155 vport_type: Read_Only
156 Reflects the FC mechanism used to create the virtual port.
157 Only NPIV is supported currently.
158
159
160 For the fc_host class object, the following attributes are added for vports:
161
162 max_npiv_vports: Read_Only
163 Indicates the maximum number of NPIV-based vports that the
164 driver/adapter can support on the fc_host.
165
166 npiv_vports_inuse: Read_Only
167 Indicates how many NPIV-based vports have been instantiated on the
168 fc_host.
169
170 vport_create: Write_Only
171 A "simple" create interface to instantiate a vport on an fc_host.
172 A "<WWPN>:<WWNN>" string is written to the attribute. The transport
173 then instantiates the vport object and calls the LLDD to create the
174 vport with the role of FCP_Initiator. Each WWN is specified as 16
175 hex characters and may *not* contain any prefixes (e.g. 0x, x, etc).
176
177 vport_delete: Write_Only
178 A "simple" delete interface to teardown a vport. A "<WWPN>:<WWNN>"
179 string is written to the attribute. The transport will locate the
180 vport on the fc_host with the same WWNs and tear it down. Each WWN
181 is specified as 16 hex characters and may *not* contain any prefixes
182 (e.g. 0x, x, etc).
183
184
185Vport States:
186-------------------------------
187
188 Vport instantiation consists of two parts:
189 - Creation with the kernel and LLDD. This means all transport and
190 driver data structures are built up, and device objects created.
191 This is equivalent to a driver "attach" on an adapter, which is
192 independent of the adapter's link state.
193 - Instantiation of the vport on the FC link via ELS traffic, etc.
194 This is equivalent to a "link up" and successfull link initialization.
195 Futher information can be found in the interfaces section below for
196 Vport Creation.
197
198 Once a vport has been instantiated with the kernel/LLDD, a vport state
199 can be reported via the sysfs attribute. The following states exist:
200
201 FC_VPORT_UNKNOWN - Unknown
202 An temporary state, typically set only while the vport is being
203 instantiated with the kernel and LLDD.
204
205 FC_VPORT_ACTIVE - Active
206 The vport has been successfully been created on the FC link.
207 It is fully functional.
208
209 FC_VPORT_DISABLED - Disabled
210 The vport instantiated, but "disabled". The vport is not instantiated
211 on the FC link. This is equivalent to a physical port with the
212 link "down".
213
214 FC_VPORT_LINKDOWN - Linkdown
215 The vport is not operational as the physical link is not operational.
216
217 FC_VPORT_INITIALIZING - Initializing
218 The vport is in the process of instantiating on the FC link.
219 The LLDD will set this state just prior to starting the ELS traffic
220 to create the vport. This state will persist until the vport is
221 successfully created (state becomes FC_VPORT_ACTIVE) or it fails
222 (state is one of the values below). As this state is transitory,
223 it will not be preserved in the "vport_last_state".
224
225 FC_VPORT_NO_FABRIC_SUPP - No Fabric Support
226 The vport is not operational. One of the following conditions were
227 encountered:
228 - The FC topology is not Point-to-Point
229 - The FC port is not connected to an F_Port
230 - The F_Port has indicated that NPIV is not supported.
231
232 FC_VPORT_NO_FABRIC_RSCS - No Fabric Resources
233 The vport is not operational. The Fabric failed FDISC with a status
234 indicating that it does not have sufficient resources to complete
235 the operation.
236
237 FC_VPORT_FABRIC_LOGOUT - Fabric Logout
238 The vport is not operational. The Fabric has LOGO'd the N_Port_ID
239 associated with the vport.
240
241 FC_VPORT_FABRIC_REJ_WWN - Fabric Rejected WWN
242 The vport is not operational. The Fabric failed FDISC with a status
243 indicating that the WWN's are not valid.
244
245 FC_VPORT_FAILED - VPort Failed
246 The vport is not operational. This is a catchall for all other
247 error conditions.
248
249
250 The following state table indicates the different state transitions:
251
252 State Event New State
253 --------------------------------------------------------------------
254 n/a Initialization Unknown
255 Unknown: Link Down Linkdown
256 Link Up & Loop No Fabric Support
257 Link Up & no Fabric No Fabric Support
258 Link Up & FLOGI response No Fabric Support
259 indicates no NPIV support
260 Link Up & FDISC being sent Initializing
261 Disable request Disable
262 Linkdown: Link Up Unknown
263 Initializing: FDISC ACC Active
264 FDISC LS_RJT w/ no resources No Fabric Resources
265 FDISC LS_RJT w/ invalid Fabric Rejected WWN
266 pname or invalid nport_id
267 FDISC LS_RJT failed for Vport Failed
268 other reasons
269 Link Down Linkdown
270 Disable request Disable
271 Disable: Enable request Unknown
272 Active: LOGO received from fabric Fabric Logout
273 Link Down Linkdown
274 Disable request Disable
275 Fabric Logout: Link still up Unknown
276
277 The following 4 error states all have the same transitions:
278 No Fabric Support:
279 No Fabric Resources:
280 Fabric Rejected WWN:
281 Vport Failed:
282 Disable request Disable
283 Link goes down Linkdown
284
285
286Transport <-> LLDD Interfaces :
287-------------------------------
288
289Vport support by LLDD:
290
291 The LLDD indicates support for vports by supplying a vport_create()
292 function in the transport template. The presense of this function will
293 cause the creation of the new attributes on the fc_host. As part of
294 the physical port completing its initialization relative to the
295 transport, it should set the max_npiv_vports attribute to indicate the
296 maximum number of vports the driver and/or adapter supports.
297
298
299Vport Creation:
300
301 The LLDD vport_create() syntax is:
302
303 int vport_create(struct fc_vport *vport, bool disable)
304
305 where:
306 vport: Is the newly allocated vport object
307 disable: If "true", the vport is to be created in a disabled stated.
308 If "false", the vport is to be enabled upon creation.
309
310 When a request is made to create a new vport (via sgio/netlink, or the
311 vport_create fc_host attribute), the transport will validate that the LLDD
312 can support another vport (e.g. max_npiv_vports > npiv_vports_inuse).
313 If not, the create request will be failed. If space remains, the transport
314 will increment the vport count, create the vport object, and then call the
315 LLDD's vport_create() function with the newly allocated vport object.
316
317 As mentioned above, vport creation is divided into two parts:
318 - Creation with the kernel and LLDD. This means all transport and
319 driver data structures are built up, and device objects created.
320 This is equivalent to a driver "attach" on an adapter, which is
321 independent of the adapter's link state.
322 - Instantiation of the vport on the FC link via ELS traffic, etc.
323 This is equivalent to a "link up" and successfull link initialization.
324
325 The LLDD's vport_create() function will not synchronously wait for both
326 parts to be fully completed before returning. It must validate that the
327 infrastructure exists to support NPIV, and complete the first part of
328 vport creation (data structure build up) before returning. We do not
329 hinge vport_create() on the link-side operation mainly because:
330 - The link may be down. It is not a failure if it is. It simply
331 means the vport is in an inoperable state until the link comes up.
332 This is consistent with the link bouncing post vport creation.
333 - The vport may be created in a disabled state.
334 - This is consistent with a model where: the vport equates to a
335 FC adapter. The vport_create is synonymous with driver attachment
336 to the adapter, which is independent of link state.
337
338 Note: special error codes have been defined to delineate infrastructure
339 failure cases for quicker resolution.
340
341 The expected behavior for the LLDD's vport_create() function is:
342 - Validate Infrastructure:
343 - If the driver or adapter cannot support another vport, whether
344 due to improper firmware, (a lie about) max_npiv, or a lack of
345 some other resource - return VPCERR_UNSUPPORTED.
346 - If the driver validates the WWN's against those already active on
347 the adapter and detects an overlap - return VPCERR_BAD_WWN.
348 - If the driver detects the topology is loop, non-fabric, or the
349 FLOGI did not support NPIV - return VPCERR_NO_FABRIC_SUPP.
350 - Allocate data structures. If errors are encountered, such as out
351 of memory conditions, return the respective negative Exxx error code.
352 - If the role is FCP Initiator, the LLDD is to :
353 - Call scsi_host_alloc() to allocate a scsi_host for the vport.
354 - Call scsi_add_host(new_shost, &vport->dev) to start the scsi_host
355 and bind it as a child of the vport device.
356 - Initializes the fc_host attribute values.
357 - Kick of further vport state transitions based on the disable flag and
358 link state - and return success (zero).
359
360 LLDD Implementers Notes:
361 - It is suggested that there be a different fc_function_templates for
362 the physical port and the virtual port. The physical port's template
363 would have the vport_create, vport_delete, and vport_disable functions,
364 while the vports would not.
365 - It is suggested that there be different scsi_host_templates
366 for the physical port and virtual port. Likely, there are driver
367 attributes, embedded into the scsi_host_template, that are applicable
368 for the physical port only (link speed, topology setting, etc). This
369 ensures that the attributes are applicable to the respective scsi_host.
370
371
372Vport Disable/Enable:
373
374 The LLDD vport_disable() syntax is:
375
376 int vport_disable(struct fc_vport *vport, bool disable)
377
378 where:
379 vport: Is vport to to be enabled or disabled
380 disable: If "true", the vport is to be disabled.
381 If "false", the vport is to be enabled.
382
383 When a request is made to change the disabled state on a vport, the
384 transport will validate the request against the existing vport state.
385 If the request is to disable and the vport is already disabled, the
386 request will fail. Similarly, if the request is to enable, and the
387 vport is not in a disabled state, the request will fail. If the request
388 is valid for the vport state, the transport will call the LLDD to
389 change the vport's state.
390
391 Within the LLDD, if a vport is disabled, it remains instantiated with
392 the kernel and LLDD, but it is not active or visible on the FC link in
393 any way. (see Vport Creation and the 2 part instantiation discussion).
394 The vport will remain in this state until it is deleted or re-enabled.
395 When enabling a vport, the LLDD reinstantiates the vport on the FC
396 link - essentially restarting the LLDD statemachine (see Vport States
397 above).
398
399
400Vport Deletion:
401
402 The LLDD vport_delete() syntax is:
403
404 int vport_delete(struct fc_vport *vport)
405
406 where:
407 vport: Is vport to delete
408
409 When a request is made to delete a vport (via sgio/netlink, or via the
410 fc_host or fc_vport vport_delete attributes), the transport will call
411 the LLDD to terminate the vport on the FC link, and teardown all other
412 datastructures and references. If the LLDD completes successfully,
413 the transport will teardown the vport objects and complete the vport
414 removal. If the LLDD delete request fails, the vport object will remain,
415 but will be in an indeterminate state.
416
417 Within the LLDD, the normal code paths for a scsi_host teardown should
418 be followed. E.g. If the vport has a FCP Initiator role, the LLDD
419 will call fc_remove_host() for the vports scsi_host, followed by
420 scsi_remove_host() and scsi_host_put() for the vports scsi_host.
421
422
423Other:
424 fc_host port_type attribute:
425 There is a new fc_host port_type value - FC_PORTTYPE_NPIV. This value
426 must be set on all vport-based fc_hosts. Normally, on a physical port,
427 the port_type attribute would be set to NPORT, NLPORT, etc based on the
428 topology type and existence of the fabric. As this is not applicable to
429 a vport, it makes more sense to report the FC mechanism used to create
430 the vport.
431
432 Driver unload:
433 FC drivers are required to call fc_remove_host() prior to calling
434 scsi_remove_host(). This allows the fc_host to tear down all remote
435 ports prior the scsi_host being torn down. The fc_remove_host() call
436 was updated to remove all vports for the fc_host as well.
437
438
439Credits
440=======
441The following people have contributed to this document:
442
443
444
445
446
447
448James Smart
449james.smart@emulex.com
450
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index b4d1ece46f78..217651468115 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -19,7 +19,7 @@
19 * 19 *
20 * ======== 20 * ========
21 * 21 *
22 * Copyright (C) 2004-2005 James Smart, Emulex Corporation 22 * Copyright (C) 2004-2007 James Smart, Emulex Corporation
23 * Rewrite for host, target, device, and remote port attributes, 23 * Rewrite for host, target, device, and remote port attributes,
24 * statistics, and service functions... 24 * statistics, and service functions...
25 * 25 *
@@ -39,6 +39,33 @@
39static int fc_queue_work(struct Scsi_Host *, struct work_struct *); 39static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
40 40
41/* 41/*
42 * This is a temporary carrier for creating a vport. It will eventually
43 * be replaced by a real message definition for sgio or netlink.
44 *
45 * fc_vport_identifiers: This set of data contains all elements
46 * to uniquely identify and instantiate a FC virtual port.
47 *
48 * Notes:
49 * symbolic_name: The driver is to append the symbolic_name string data
50 * to the symbolic_node_name data that it generates by default.
51 * the resulting combination should then be registered with the switch.
52 * It is expected that things like Xen may stuff a VM title into
53 * this field.
54 */
55struct fc_vport_identifiers {
56 u64 node_name;
57 u64 port_name;
58 u32 roles;
59 bool disable;
60 enum fc_port_type vport_type; /* only FC_PORTTYPE_NPIV allowed */
61 char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];
62};
63
64static int fc_vport_create(struct Scsi_Host *shost, int channel,
65 struct device *pdev, struct fc_vport_identifiers *ids,
66 struct fc_vport **vport);
67
68/*
42 * Redefine so that we can have same named attributes in the 69 * Redefine so that we can have same named attributes in the
43 * sdev/starget/host objects. 70 * sdev/starget/host objects.
44 */ 71 */
@@ -90,10 +117,14 @@ static struct {
90 { FC_PORTTYPE_NLPORT, "NLPort (fabric via loop)" }, 117 { FC_PORTTYPE_NLPORT, "NLPort (fabric via loop)" },
91 { FC_PORTTYPE_LPORT, "LPort (private loop)" }, 118 { FC_PORTTYPE_LPORT, "LPort (private loop)" },
92 { FC_PORTTYPE_PTP, "Point-To-Point (direct nport connection" }, 119 { FC_PORTTYPE_PTP, "Point-To-Point (direct nport connection" },
120 { FC_PORTTYPE_NPIV, "NPIV VPORT" },
93}; 121};
94fc_enum_name_search(port_type, fc_port_type, fc_port_type_names) 122fc_enum_name_search(port_type, fc_port_type, fc_port_type_names)
95#define FC_PORTTYPE_MAX_NAMELEN 50 123#define FC_PORTTYPE_MAX_NAMELEN 50
96 124
125/* Reuse fc_port_type enum function for vport_type */
126#define get_fc_vport_type_name get_fc_port_type_name
127
97 128
98/* Convert fc_host_event_code values to ascii string name */ 129/* Convert fc_host_event_code values to ascii string name */
99static const struct { 130static const struct {
@@ -139,6 +170,29 @@ fc_enum_name_search(port_state, fc_port_state, fc_port_state_names)
139#define FC_PORTSTATE_MAX_NAMELEN 20 170#define FC_PORTSTATE_MAX_NAMELEN 20
140 171
141 172
173/* Convert fc_vport_state values to ascii string name */
174static struct {
175 enum fc_vport_state value;
176 char *name;
177} fc_vport_state_names[] = {
178 { FC_VPORT_UNKNOWN, "Unknown" },
179 { FC_VPORT_ACTIVE, "Active" },
180 { FC_VPORT_DISABLED, "Disabled" },
181 { FC_VPORT_LINKDOWN, "Linkdown" },
182 { FC_VPORT_INITIALIZING, "Initializing" },
183 { FC_VPORT_NO_FABRIC_SUPP, "No Fabric Support" },
184 { FC_VPORT_NO_FABRIC_RSCS, "No Fabric Resources" },
185 { FC_VPORT_FABRIC_LOGOUT, "Fabric Logout" },
186 { FC_VPORT_FABRIC_REJ_WWN, "Fabric Rejected WWN" },
187 { FC_VPORT_FAILED, "VPort Failed" },
188};
189fc_enum_name_search(vport_state, fc_vport_state, fc_vport_state_names)
190#define FC_VPORTSTATE_MAX_NAMELEN 24
191
192/* Reuse fc_vport_state enum function for vport_last_state */
193#define get_fc_vport_last_state_name get_fc_vport_state_name
194
195
142/* Convert fc_tgtid_binding_type values to ascii string name */ 196/* Convert fc_tgtid_binding_type values to ascii string name */
143static const struct { 197static const struct {
144 enum fc_tgtid_binding_type value; 198 enum fc_tgtid_binding_type value;
@@ -219,16 +273,16 @@ show_fc_fc4s (char *buf, u8 *fc4_list)
219} 273}
220 274
221 275
222/* Convert FC_RPORT_ROLE bit values to ascii string name */ 276/* Convert FC_PORT_ROLE bit values to ascii string name */
223static const struct { 277static const struct {
224 u32 value; 278 u32 value;
225 char *name; 279 char *name;
226} fc_remote_port_role_names[] = { 280} fc_port_role_names[] = {
227 { FC_RPORT_ROLE_FCP_TARGET, "FCP Target" }, 281 { FC_PORT_ROLE_FCP_TARGET, "FCP Target" },
228 { FC_RPORT_ROLE_FCP_INITIATOR, "FCP Initiator" }, 282 { FC_PORT_ROLE_FCP_INITIATOR, "FCP Initiator" },
229 { FC_RPORT_ROLE_IP_PORT, "IP Port" }, 283 { FC_PORT_ROLE_IP_PORT, "IP Port" },
230}; 284};
231fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names) 285fc_bitfield_name_search(port_roles, fc_port_role_names)
232 286
233/* 287/*
234 * Define roles that are specific to port_id. Values are relative to ROLE_MASK. 288 * Define roles that are specific to port_id. Values are relative to ROLE_MASK.
@@ -252,7 +306,8 @@ static void fc_scsi_scan_rport(struct work_struct *work);
252 */ 306 */
253#define FC_STARGET_NUM_ATTRS 3 307#define FC_STARGET_NUM_ATTRS 3
254#define FC_RPORT_NUM_ATTRS 10 308#define FC_RPORT_NUM_ATTRS 10
255#define FC_HOST_NUM_ATTRS 17 309#define FC_VPORT_NUM_ATTRS 9
310#define FC_HOST_NUM_ATTRS 21
256 311
257struct fc_internal { 312struct fc_internal {
258 struct scsi_transport_template t; 313 struct scsi_transport_template t;
@@ -278,6 +333,10 @@ struct fc_internal {
278 struct transport_container rport_attr_cont; 333 struct transport_container rport_attr_cont;
279 struct class_device_attribute private_rport_attrs[FC_RPORT_NUM_ATTRS]; 334 struct class_device_attribute private_rport_attrs[FC_RPORT_NUM_ATTRS];
280 struct class_device_attribute *rport_attrs[FC_RPORT_NUM_ATTRS + 1]; 335 struct class_device_attribute *rport_attrs[FC_RPORT_NUM_ATTRS + 1];
336
337 struct transport_container vport_attr_cont;
338 struct class_device_attribute private_vport_attrs[FC_VPORT_NUM_ATTRS];
339 struct class_device_attribute *vport_attrs[FC_VPORT_NUM_ATTRS + 1];
281}; 340};
282 341
283#define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t) 342#define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t)
@@ -331,6 +390,7 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
331 sizeof(fc_host->supported_fc4s)); 390 sizeof(fc_host->supported_fc4s));
332 fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN; 391 fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN;
333 fc_host->maxframe_size = -1; 392 fc_host->maxframe_size = -1;
393 fc_host->max_npiv_vports = 0;
334 memset(fc_host->serial_number, 0, 394 memset(fc_host->serial_number, 0,
335 sizeof(fc_host->serial_number)); 395 sizeof(fc_host->serial_number));
336 396
@@ -348,8 +408,11 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
348 408
349 INIT_LIST_HEAD(&fc_host->rports); 409 INIT_LIST_HEAD(&fc_host->rports);
350 INIT_LIST_HEAD(&fc_host->rport_bindings); 410 INIT_LIST_HEAD(&fc_host->rport_bindings);
411 INIT_LIST_HEAD(&fc_host->vports);
351 fc_host->next_rport_number = 0; 412 fc_host->next_rport_number = 0;
352 fc_host->next_target_id = 0; 413 fc_host->next_target_id = 0;
414 fc_host->next_vport_number = 0;
415 fc_host->npiv_vports_inuse = 0;
353 416
354 snprintf(fc_host->work_q_name, KOBJ_NAME_LEN, "fc_wq_%d", 417 snprintf(fc_host->work_q_name, KOBJ_NAME_LEN, "fc_wq_%d",
355 shost->host_no); 418 shost->host_no);
@@ -388,6 +451,16 @@ static DECLARE_TRANSPORT_CLASS(fc_rport_class,
388 NULL); 451 NULL);
389 452
390/* 453/*
454 * Setup and Remove actions for virtual ports are handled
455 * in the service functions below.
456 */
457static DECLARE_TRANSPORT_CLASS(fc_vport_class,
458 "fc_vports",
459 NULL,
460 NULL,
461 NULL);
462
463/*
391 * Module Parameters 464 * Module Parameters
392 */ 465 */
393 466
@@ -585,6 +658,9 @@ static __init int fc_transport_init(void)
585 error = transport_class_register(&fc_host_class); 658 error = transport_class_register(&fc_host_class);
586 if (error) 659 if (error)
587 return error; 660 return error;
661 error = transport_class_register(&fc_vport_class);
662 if (error)
663 return error;
588 error = transport_class_register(&fc_rport_class); 664 error = transport_class_register(&fc_rport_class);
589 if (error) 665 if (error)
590 return error; 666 return error;
@@ -596,6 +672,7 @@ static void __exit fc_transport_exit(void)
596 transport_class_unregister(&fc_transport_class); 672 transport_class_unregister(&fc_transport_class);
597 transport_class_unregister(&fc_rport_class); 673 transport_class_unregister(&fc_rport_class);
598 transport_class_unregister(&fc_host_class); 674 transport_class_unregister(&fc_host_class);
675 transport_class_unregister(&fc_vport_class);
599} 676}
600 677
601/* 678/*
@@ -800,9 +877,9 @@ show_fc_rport_roles (struct class_device *cdev, char *buf)
800 return snprintf(buf, 30, "Unknown Fabric Entity\n"); 877 return snprintf(buf, 30, "Unknown Fabric Entity\n");
801 } 878 }
802 } else { 879 } else {
803 if (rport->roles == FC_RPORT_ROLE_UNKNOWN) 880 if (rport->roles == FC_PORT_ROLE_UNKNOWN)
804 return snprintf(buf, 20, "unknown\n"); 881 return snprintf(buf, 20, "unknown\n");
805 return get_fc_remote_port_roles_names(rport->roles, buf); 882 return get_fc_port_roles_names(rport->roles, buf);
806 } 883 }
807} 884}
808static FC_CLASS_DEVICE_ATTR(rport, roles, S_IRUGO, 885static FC_CLASS_DEVICE_ATTR(rport, roles, S_IRUGO,
@@ -857,7 +934,7 @@ static FC_CLASS_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR,
857 934
858/* 935/*
859 * Note: in the target show function we recognize when the remote 936 * Note: in the target show function we recognize when the remote
860 * port is in the hierarchy and do not allow the driver to get 937 * port is in the heirarchy and do not allow the driver to get
861 * involved in sysfs functions. The driver only gets involved if 938 * involved in sysfs functions. The driver only gets involved if
862 * it's the "old" style that doesn't use rports. 939 * it's the "old" style that doesn't use rports.
863 */ 940 */
@@ -912,6 +989,260 @@ fc_starget_rd_attr(port_id, "0x%06x\n", 20);
912 989
913 990
914/* 991/*
992 * FC Virtual Port Attribute Management
993 */
994
995#define fc_vport_show_function(field, format_string, sz, cast) \
996static ssize_t \
997show_fc_vport_##field (struct class_device *cdev, char *buf) \
998{ \
999 struct fc_vport *vport = transport_class_to_vport(cdev); \
1000 struct Scsi_Host *shost = vport_to_shost(vport); \
1001 struct fc_internal *i = to_fc_internal(shost->transportt); \
1002 if ((i->f->get_vport_##field) && \
1003 !(vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING))) \
1004 i->f->get_vport_##field(vport); \
1005 return snprintf(buf, sz, format_string, cast vport->field); \
1006}
1007
1008#define fc_vport_store_function(field) \
1009static ssize_t \
1010store_fc_vport_##field(struct class_device *cdev, const char *buf, \
1011 size_t count) \
1012{ \
1013 int val; \
1014 struct fc_vport *vport = transport_class_to_vport(cdev); \
1015 struct Scsi_Host *shost = vport_to_shost(vport); \
1016 struct fc_internal *i = to_fc_internal(shost->transportt); \
1017 char *cp; \
1018 if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) \
1019 return -EBUSY; \
1020 val = simple_strtoul(buf, &cp, 0); \
1021 if (*cp && (*cp != '\n')) \
1022 return -EINVAL; \
1023 i->f->set_vport_##field(vport, val); \
1024 return count; \
1025}
1026
1027#define fc_vport_store_str_function(field, slen) \
1028static ssize_t \
1029store_fc_vport_##field(struct class_device *cdev, const char *buf, \
1030 size_t count) \
1031{ \
1032 struct fc_vport *vport = transport_class_to_vport(cdev); \
1033 struct Scsi_Host *shost = vport_to_shost(vport); \
1034 struct fc_internal *i = to_fc_internal(shost->transportt); \
1035 unsigned int cnt=count; \
1036 \
1037 /* count may include a LF at end of string */ \
1038 if (buf[cnt-1] == '\n') \
1039 cnt--; \
1040 if (cnt > ((slen) - 1)) \
1041 return -EINVAL; \
1042 memcpy(vport->field, buf, cnt); \
1043 i->f->set_vport_##field(vport); \
1044 return count; \
1045}
1046
1047#define fc_vport_rd_attr(field, format_string, sz) \
1048 fc_vport_show_function(field, format_string, sz, ) \
1049static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO, \
1050 show_fc_vport_##field, NULL)
1051
1052#define fc_vport_rd_attr_cast(field, format_string, sz, cast) \
1053 fc_vport_show_function(field, format_string, sz, (cast)) \
1054static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO, \
1055 show_fc_vport_##field, NULL)
1056
1057#define fc_vport_rw_attr(field, format_string, sz) \
1058 fc_vport_show_function(field, format_string, sz, ) \
1059 fc_vport_store_function(field) \
1060static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO | S_IWUSR, \
1061 show_fc_vport_##field, \
1062 store_fc_vport_##field)
1063
1064#define fc_private_vport_show_function(field, format_string, sz, cast) \
1065static ssize_t \
1066show_fc_vport_##field (struct class_device *cdev, char *buf) \
1067{ \
1068 struct fc_vport *vport = transport_class_to_vport(cdev); \
1069 return snprintf(buf, sz, format_string, cast vport->field); \
1070}
1071
1072#define fc_private_vport_store_u32_function(field) \
1073static ssize_t \
1074store_fc_vport_##field(struct class_device *cdev, const char *buf, \
1075 size_t count) \
1076{ \
1077 u32 val; \
1078 struct fc_vport *vport = transport_class_to_vport(cdev); \
1079 char *cp; \
1080 if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) \
1081 return -EBUSY; \
1082 val = simple_strtoul(buf, &cp, 0); \
1083 if (*cp && (*cp != '\n')) \
1084 return -EINVAL; \
1085 vport->field = val; \
1086 return count; \
1087}
1088
1089
1090#define fc_private_vport_rd_attr(field, format_string, sz) \
1091 fc_private_vport_show_function(field, format_string, sz, ) \
1092static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO, \
1093 show_fc_vport_##field, NULL)
1094
1095#define fc_private_vport_rd_attr_cast(field, format_string, sz, cast) \
1096 fc_private_vport_show_function(field, format_string, sz, (cast)) \
1097static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO, \
1098 show_fc_vport_##field, NULL)
1099
1100#define fc_private_vport_rw_u32_attr(field, format_string, sz) \
1101 fc_private_vport_show_function(field, format_string, sz, ) \
1102 fc_private_vport_store_u32_function(field) \
1103static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO | S_IWUSR, \
1104 show_fc_vport_##field, \
1105 store_fc_vport_##field)
1106
1107
1108#define fc_private_vport_rd_enum_attr(title, maxlen) \
1109static ssize_t \
1110show_fc_vport_##title (struct class_device *cdev, char *buf) \
1111{ \
1112 struct fc_vport *vport = transport_class_to_vport(cdev); \
1113 const char *name; \
1114 name = get_fc_##title##_name(vport->title); \
1115 if (!name) \
1116 return -EINVAL; \
1117 return snprintf(buf, maxlen, "%s\n", name); \
1118} \
1119static FC_CLASS_DEVICE_ATTR(vport, title, S_IRUGO, \
1120 show_fc_vport_##title, NULL)
1121
1122
1123#define SETUP_VPORT_ATTRIBUTE_RD(field) \
1124 i->private_vport_attrs[count] = class_device_attr_vport_##field; \
1125 i->private_vport_attrs[count].attr.mode = S_IRUGO; \
1126 i->private_vport_attrs[count].store = NULL; \
1127 i->vport_attrs[count] = &i->private_vport_attrs[count]; \
1128 if (i->f->get_##field) \
1129 count++
1130 /* NOTE: Above MACRO differs: checks function not show bit */
1131
1132#define SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(field) \
1133 i->private_vport_attrs[count] = class_device_attr_vport_##field; \
1134 i->private_vport_attrs[count].attr.mode = S_IRUGO; \
1135 i->private_vport_attrs[count].store = NULL; \
1136 i->vport_attrs[count] = &i->private_vport_attrs[count]; \
1137 count++
1138
1139#define SETUP_VPORT_ATTRIBUTE_WR(field) \
1140 i->private_vport_attrs[count] = class_device_attr_vport_##field; \
1141 i->vport_attrs[count] = &i->private_vport_attrs[count]; \
1142 if (i->f->field) \
1143 count++
1144 /* NOTE: Above MACRO differs: checks function */
1145
1146#define SETUP_VPORT_ATTRIBUTE_RW(field) \
1147 i->private_vport_attrs[count] = class_device_attr_vport_##field; \
1148 if (!i->f->set_vport_##field) { \
1149 i->private_vport_attrs[count].attr.mode = S_IRUGO; \
1150 i->private_vport_attrs[count].store = NULL; \
1151 } \
1152 i->vport_attrs[count] = &i->private_vport_attrs[count]; \
1153 count++
1154 /* NOTE: Above MACRO differs: does not check show bit */
1155
1156#define SETUP_PRIVATE_VPORT_ATTRIBUTE_RW(field) \
1157{ \
1158 i->private_vport_attrs[count] = class_device_attr_vport_##field; \
1159 i->vport_attrs[count] = &i->private_vport_attrs[count]; \
1160 count++; \
1161}
1162
1163
1164/* The FC Transport Virtual Port Attributes: */
1165
1166/* Fixed Virtual Port Attributes */
1167
1168/* Dynamic Virtual Port Attributes */
1169
1170/* Private Virtual Port Attributes */
1171
1172fc_private_vport_rd_enum_attr(vport_state, FC_VPORTSTATE_MAX_NAMELEN);
1173fc_private_vport_rd_enum_attr(vport_last_state, FC_VPORTSTATE_MAX_NAMELEN);
1174fc_private_vport_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long);
1175fc_private_vport_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
1176
1177static ssize_t
1178show_fc_vport_roles (struct class_device *cdev, char *buf)
1179{
1180 struct fc_vport *vport = transport_class_to_vport(cdev);
1181
1182 if (vport->roles == FC_PORT_ROLE_UNKNOWN)
1183 return snprintf(buf, 20, "unknown\n");
1184 return get_fc_port_roles_names(vport->roles, buf);
1185}
1186static FC_CLASS_DEVICE_ATTR(vport, roles, S_IRUGO, show_fc_vport_roles, NULL);
1187
1188fc_private_vport_rd_enum_attr(vport_type, FC_PORTTYPE_MAX_NAMELEN);
1189
1190fc_private_vport_show_function(symbolic_name, "%s\n",
1191 FC_VPORT_SYMBOLIC_NAMELEN + 1, )
1192fc_vport_store_str_function(symbolic_name, FC_VPORT_SYMBOLIC_NAMELEN)
1193static FC_CLASS_DEVICE_ATTR(vport, symbolic_name, S_IRUGO | S_IWUSR,
1194 show_fc_vport_symbolic_name, store_fc_vport_symbolic_name);
1195
1196static ssize_t
1197store_fc_vport_delete(struct class_device *cdev, const char *buf,
1198 size_t count)
1199{
1200 struct fc_vport *vport = transport_class_to_vport(cdev);
1201 int stat;
1202
1203 stat = fc_vport_terminate(vport);
1204 if (stat)
1205 return stat;
1206
1207 return count;
1208}
1209static FC_CLASS_DEVICE_ATTR(vport, vport_delete, S_IWUSR,
1210 NULL, store_fc_vport_delete);
1211
1212
1213/*
1214 * Enable/Disable vport
1215 * Write "1" to disable, write "0" to enable
1216 */
1217static ssize_t
1218store_fc_vport_disable(struct class_device *cdev, const char *buf,
1219 size_t count)
1220{
1221 struct fc_vport *vport = transport_class_to_vport(cdev);
1222 struct Scsi_Host *shost = vport_to_shost(vport);
1223 struct fc_internal *i = to_fc_internal(shost->transportt);
1224 int stat;
1225
1226 if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING))
1227 return -EBUSY;
1228
1229 if (*buf == '0') {
1230 if (vport->vport_state != FC_VPORT_DISABLED)
1231 return -EALREADY;
1232 } else if (*buf == '1') {
1233 if (vport->vport_state == FC_VPORT_DISABLED)
1234 return -EALREADY;
1235 } else
1236 return -EINVAL;
1237
1238 stat = i->f->vport_disable(vport, ((*buf == '0') ? false : true));
1239 return stat ? stat : count;
1240}
1241static FC_CLASS_DEVICE_ATTR(vport, vport_disable, S_IWUSR,
1242 NULL, store_fc_vport_disable);
1243
1244
1245/*
915 * Host Attribute Management 1246 * Host Attribute Management
916 */ 1247 */
917 1248
@@ -1003,6 +1334,13 @@ static FC_CLASS_DEVICE_ATTR(host, title, S_IRUGO, show_fc_host_##title, NULL)
1003 if (i->f->show_host_##field) \ 1334 if (i->f->show_host_##field) \
1004 count++ 1335 count++
1005 1336
1337#define SETUP_HOST_ATTRIBUTE_RD_NS(field) \
1338 i->private_host_attrs[count] = class_device_attr_host_##field; \
1339 i->private_host_attrs[count].attr.mode = S_IRUGO; \
1340 i->private_host_attrs[count].store = NULL; \
1341 i->host_attrs[count] = &i->private_host_attrs[count]; \
1342 count++
1343
1006#define SETUP_HOST_ATTRIBUTE_RW(field) \ 1344#define SETUP_HOST_ATTRIBUTE_RW(field) \
1007 i->private_host_attrs[count] = class_device_attr_host_##field; \ 1345 i->private_host_attrs[count] = class_device_attr_host_##field; \
1008 if (!i->f->set_host_##field) { \ 1346 if (!i->f->set_host_##field) { \
@@ -1090,6 +1428,7 @@ fc_private_host_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
1090fc_private_host_rd_attr_cast(permanent_port_name, "0x%llx\n", 20, 1428fc_private_host_rd_attr_cast(permanent_port_name, "0x%llx\n", 20,
1091 unsigned long long); 1429 unsigned long long);
1092fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20); 1430fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20);
1431fc_private_host_rd_attr(max_npiv_vports, "%u\n", 20);
1093fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1)); 1432fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1));
1094 1433
1095 1434
@@ -1210,6 +1549,9 @@ store_fc_private_host_issue_lip(struct class_device *cdev,
1210static FC_CLASS_DEVICE_ATTR(host, issue_lip, S_IWUSR, NULL, 1549static FC_CLASS_DEVICE_ATTR(host, issue_lip, S_IWUSR, NULL,
1211 store_fc_private_host_issue_lip); 1550 store_fc_private_host_issue_lip);
1212 1551
1552fc_private_host_rd_attr(npiv_vports_inuse, "%u\n", 20);
1553
1554
1213/* 1555/*
1214 * Host Statistics Management 1556 * Host Statistics Management
1215 */ 1557 */
@@ -1285,7 +1627,6 @@ fc_reset_statistics(struct class_device *cdev, const char *buf,
1285static FC_CLASS_DEVICE_ATTR(host, reset_statistics, S_IWUSR, NULL, 1627static FC_CLASS_DEVICE_ATTR(host, reset_statistics, S_IWUSR, NULL,
1286 fc_reset_statistics); 1628 fc_reset_statistics);
1287 1629
1288
1289static struct attribute *fc_statistics_attrs[] = { 1630static struct attribute *fc_statistics_attrs[] = {
1290 &class_device_attr_host_seconds_since_last_reset.attr, 1631 &class_device_attr_host_seconds_since_last_reset.attr,
1291 &class_device_attr_host_tx_frames.attr, 1632 &class_device_attr_host_tx_frames.attr,
@@ -1316,6 +1657,142 @@ static struct attribute_group fc_statistics_group = {
1316 .attrs = fc_statistics_attrs, 1657 .attrs = fc_statistics_attrs,
1317}; 1658};
1318 1659
1660
1661/* Host Vport Attributes */
1662
1663static int
1664fc_parse_wwn(const char *ns, u64 *nm)
1665{
1666 unsigned int i, j;
1667 u8 wwn[8];
1668
1669 memset(wwn, 0, sizeof(wwn));
1670
1671 /* Validate and store the new name */
1672 for (i=0, j=0; i < 16; i++) {
1673 if ((*ns >= 'a') && (*ns <= 'f'))
1674 j = ((j << 4) | ((*ns++ -'a') + 10));
1675 else if ((*ns >= 'A') && (*ns <= 'F'))
1676 j = ((j << 4) | ((*ns++ -'A') + 10));
1677 else if ((*ns >= '0') && (*ns <= '9'))
1678 j = ((j << 4) | (*ns++ -'0'));
1679 else
1680 return -EINVAL;
1681 if (i % 2) {
1682 wwn[i/2] = j & 0xff;
1683 j = 0;
1684 }
1685 }
1686
1687 *nm = wwn_to_u64(wwn);
1688
1689 return 0;
1690}
1691
1692
1693/*
1694 * "Short-cut" sysfs variable to create a new vport on a FC Host.
1695 * Input is a string of the form "<WWPN>:<WWNN>". Other attributes
1696 * will default to a NPIV-based FCP_Initiator; The WWNs are specified
1697 * as hex characters, and may *not* contain any prefixes (e.g. 0x, x, etc)
1698 */
1699static ssize_t
1700store_fc_host_vport_create(struct class_device *cdev, const char *buf,
1701 size_t count)
1702{
1703 struct Scsi_Host *shost = transport_class_to_shost(cdev);
1704 struct fc_vport_identifiers vid;
1705 struct fc_vport *vport;
1706 unsigned int cnt=count;
1707 int stat;
1708
1709 memset(&vid, 0, sizeof(vid));
1710
1711 /* count may include a LF at end of string */
1712 if (buf[cnt-1] == '\n')
1713 cnt--;
1714
1715 /* validate we have enough characters for WWPN */
1716 if ((cnt != (16+1+16)) || (buf[16] != ':'))
1717 return -EINVAL;
1718
1719 stat = fc_parse_wwn(&buf[0], &vid.port_name);
1720 if (stat)
1721 return stat;
1722
1723 stat = fc_parse_wwn(&buf[17], &vid.node_name);
1724 if (stat)
1725 return stat;
1726
1727 vid.roles = FC_PORT_ROLE_FCP_INITIATOR;
1728 vid.vport_type = FC_PORTTYPE_NPIV;
1729 /* vid.symbolic_name is already zero/NULL's */
1730 vid.disable = false; /* always enabled */
1731
1732 /* we only allow support on Channel 0 !!! */
1733 stat = fc_vport_create(shost, 0, &shost->shost_gendev, &vid, &vport);
1734 return stat ? stat : count;
1735}
1736static FC_CLASS_DEVICE_ATTR(host, vport_create, S_IWUSR, NULL,
1737 store_fc_host_vport_create);
1738
1739
1740/*
1741 * "Short-cut" sysfs variable to delete a vport on a FC Host.
1742 * Vport is identified by a string containing "<WWPN>:<WWNN>".
1743 * The WWNs are specified as hex characters, and may *not* contain
1744 * any prefixes (e.g. 0x, x, etc)
1745 */
1746static ssize_t
1747store_fc_host_vport_delete(struct class_device *cdev, const char *buf,
1748 size_t count)
1749{
1750 struct Scsi_Host *shost = transport_class_to_shost(cdev);
1751 struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
1752 struct fc_vport *vport;
1753 u64 wwpn, wwnn;
1754 unsigned long flags;
1755 unsigned int cnt=count;
1756 int stat, match;
1757
1758 /* count may include a LF at end of string */
1759 if (buf[cnt-1] == '\n')
1760 cnt--;
1761
1762 /* validate we have enough characters for WWPN */
1763 if ((cnt != (16+1+16)) || (buf[16] != ':'))
1764 return -EINVAL;
1765
1766 stat = fc_parse_wwn(&buf[0], &wwpn);
1767 if (stat)
1768 return stat;
1769
1770 stat = fc_parse_wwn(&buf[17], &wwnn);
1771 if (stat)
1772 return stat;
1773
1774 spin_lock_irqsave(shost->host_lock, flags);
1775 match = 0;
1776 /* we only allow support on Channel 0 !!! */
1777 list_for_each_entry(vport, &fc_host->vports, peers) {
1778 if ((vport->channel == 0) &&
1779 (vport->port_name == wwpn) && (vport->node_name == wwnn)) {
1780 match = 1;
1781 break;
1782 }
1783 }
1784 spin_unlock_irqrestore(shost->host_lock, flags);
1785
1786 if (!match)
1787 return -ENODEV;
1788
1789 stat = fc_vport_terminate(vport);
1790 return stat ? stat : count;
1791}
1792static FC_CLASS_DEVICE_ATTR(host, vport_delete, S_IWUSR, NULL,
1793 store_fc_host_vport_delete);
1794
1795
1319static int fc_host_match(struct attribute_container *cont, 1796static int fc_host_match(struct attribute_container *cont,
1320 struct device *dev) 1797 struct device *dev)
1321{ 1798{
@@ -1387,6 +1864,40 @@ static int fc_rport_match(struct attribute_container *cont,
1387} 1864}
1388 1865
1389 1866
1867static void fc_vport_dev_release(struct device *dev)
1868{
1869 struct fc_vport *vport = dev_to_vport(dev);
1870 put_device(dev->parent); /* release kobj parent */
1871 kfree(vport);
1872}
1873
1874int scsi_is_fc_vport(const struct device *dev)
1875{
1876 return dev->release == fc_vport_dev_release;
1877}
1878EXPORT_SYMBOL(scsi_is_fc_vport);
1879
1880static int fc_vport_match(struct attribute_container *cont,
1881 struct device *dev)
1882{
1883 struct fc_vport *vport;
1884 struct Scsi_Host *shost;
1885 struct fc_internal *i;
1886
1887 if (!scsi_is_fc_vport(dev))
1888 return 0;
1889 vport = dev_to_vport(dev);
1890
1891 shost = vport_to_shost(vport);
1892 if (!shost->transportt || shost->transportt->host_attrs.ac.class
1893 != &fc_host_class.class)
1894 return 0;
1895
1896 i = to_fc_internal(shost->transportt);
1897 return &i->vport_attr_cont.ac == cont;
1898}
1899
1900
1390/** 1901/**
1391 * fc_timed_out - FC Transport I/O timeout intercept handler 1902 * fc_timed_out - FC Transport I/O timeout intercept handler
1392 * 1903 *
@@ -1472,6 +1983,11 @@ fc_attach_transport(struct fc_function_template *ft)
1472 i->rport_attr_cont.ac.match = fc_rport_match; 1983 i->rport_attr_cont.ac.match = fc_rport_match;
1473 transport_container_register(&i->rport_attr_cont); 1984 transport_container_register(&i->rport_attr_cont);
1474 1985
1986 i->vport_attr_cont.ac.attrs = &i->vport_attrs[0];
1987 i->vport_attr_cont.ac.class = &fc_vport_class.class;
1988 i->vport_attr_cont.ac.match = fc_vport_match;
1989 transport_container_register(&i->vport_attr_cont);
1990
1475 i->f = ft; 1991 i->f = ft;
1476 1992
1477 /* Transport uses the shost workq for scsi scanning */ 1993 /* Transport uses the shost workq for scsi scanning */
@@ -1505,6 +2021,10 @@ fc_attach_transport(struct fc_function_template *ft)
1505 SETUP_HOST_ATTRIBUTE_RD(supported_fc4s); 2021 SETUP_HOST_ATTRIBUTE_RD(supported_fc4s);
1506 SETUP_HOST_ATTRIBUTE_RD(supported_speeds); 2022 SETUP_HOST_ATTRIBUTE_RD(supported_speeds);
1507 SETUP_HOST_ATTRIBUTE_RD(maxframe_size); 2023 SETUP_HOST_ATTRIBUTE_RD(maxframe_size);
2024 if (ft->vport_create) {
2025 SETUP_HOST_ATTRIBUTE_RD_NS(max_npiv_vports);
2026 SETUP_HOST_ATTRIBUTE_RD_NS(npiv_vports_inuse);
2027 }
1508 SETUP_HOST_ATTRIBUTE_RD(serial_number); 2028 SETUP_HOST_ATTRIBUTE_RD(serial_number);
1509 2029
1510 SETUP_HOST_ATTRIBUTE_RD(port_id); 2030 SETUP_HOST_ATTRIBUTE_RD(port_id);
@@ -1520,6 +2040,10 @@ fc_attach_transport(struct fc_function_template *ft)
1520 SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type); 2040 SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type);
1521 if (ft->issue_fc_host_lip) 2041 if (ft->issue_fc_host_lip)
1522 SETUP_PRIVATE_HOST_ATTRIBUTE_RW(issue_lip); 2042 SETUP_PRIVATE_HOST_ATTRIBUTE_RW(issue_lip);
2043 if (ft->vport_create)
2044 SETUP_PRIVATE_HOST_ATTRIBUTE_RW(vport_create);
2045 if (ft->vport_delete)
2046 SETUP_PRIVATE_HOST_ATTRIBUTE_RW(vport_delete);
1523 2047
1524 BUG_ON(count > FC_HOST_NUM_ATTRS); 2048 BUG_ON(count > FC_HOST_NUM_ATTRS);
1525 2049
@@ -1545,6 +2069,24 @@ fc_attach_transport(struct fc_function_template *ft)
1545 2069
1546 i->rport_attrs[count] = NULL; 2070 i->rport_attrs[count] = NULL;
1547 2071
2072 /*
2073 * Setup Virtual Port Attributes.
2074 */
2075 count=0;
2076 SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(vport_state);
2077 SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(vport_last_state);
2078 SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(node_name);
2079 SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(port_name);
2080 SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(roles);
2081 SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(vport_type);
2082 SETUP_VPORT_ATTRIBUTE_RW(symbolic_name);
2083 SETUP_VPORT_ATTRIBUTE_WR(vport_delete);
2084 SETUP_VPORT_ATTRIBUTE_WR(vport_disable);
2085
2086 BUG_ON(count > FC_VPORT_NUM_ATTRS);
2087
2088 i->vport_attrs[count] = NULL;
2089
1548 return &i->t; 2090 return &i->t;
1549} 2091}
1550EXPORT_SYMBOL(fc_attach_transport); 2092EXPORT_SYMBOL(fc_attach_transport);
@@ -1556,6 +2098,7 @@ void fc_release_transport(struct scsi_transport_template *t)
1556 transport_container_unregister(&i->t.target_attrs); 2098 transport_container_unregister(&i->t.target_attrs);
1557 transport_container_unregister(&i->t.host_attrs); 2099 transport_container_unregister(&i->t.host_attrs);
1558 transport_container_unregister(&i->rport_attr_cont); 2100 transport_container_unregister(&i->rport_attr_cont);
2101 transport_container_unregister(&i->vport_attr_cont);
1559 2102
1560 kfree(i); 2103 kfree(i);
1561} 2104}
@@ -1667,9 +2210,28 @@ fc_flush_devloss(struct Scsi_Host *shost)
1667void 2210void
1668fc_remove_host(struct Scsi_Host *shost) 2211fc_remove_host(struct Scsi_Host *shost)
1669{ 2212{
1670 struct fc_rport *rport, *next_rport; 2213 struct fc_vport *vport = NULL, *next_vport = NULL;
2214 struct fc_rport *rport = NULL, *next_rport = NULL;
1671 struct workqueue_struct *work_q; 2215 struct workqueue_struct *work_q;
1672 struct fc_host_attrs *fc_host = shost_to_fc_host(shost); 2216 struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
2217 unsigned long flags;
2218 int stat;
2219
2220 spin_lock_irqsave(shost->host_lock, flags);
2221
2222 /* Remove any vports */
2223 list_for_each_entry_safe(vport, next_vport, &fc_host->vports, peers) {
2224 spin_unlock_irqrestore(shost->host_lock, flags);
2225 /* this must be called synchronously */
2226 stat = fc_vport_terminate(vport);
2227 spin_lock_irqsave(shost->host_lock, flags);
2228 if (stat)
2229 dev_printk(KERN_ERR, vport->dev.parent,
2230 "%s: %s could not be deleted created via "
2231 "shost%d channel %d\n", __FUNCTION__,
2232 vport->dev.bus_id, vport->shost->host_no,
2233 vport->channel);
2234 }
1673 2235
1674 /* Remove any remote ports */ 2236 /* Remove any remote ports */
1675 list_for_each_entry_safe(rport, next_rport, 2237 list_for_each_entry_safe(rport, next_rport,
@@ -1686,6 +2248,8 @@ fc_remove_host(struct Scsi_Host *shost)
1686 fc_queue_work(shost, &rport->rport_delete_work); 2248 fc_queue_work(shost, &rport->rport_delete_work);
1687 } 2249 }
1688 2250
2251 spin_unlock_irqrestore(shost->host_lock, flags);
2252
1689 /* flush all scan work items */ 2253 /* flush all scan work items */
1690 scsi_flush_work(shost); 2254 scsi_flush_work(shost);
1691 2255
@@ -1844,7 +2408,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
1844 spin_lock_irqsave(shost->host_lock, flags); 2408 spin_lock_irqsave(shost->host_lock, flags);
1845 2409
1846 rport->number = fc_host->next_rport_number++; 2410 rport->number = fc_host->next_rport_number++;
1847 if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) 2411 if (rport->roles & FC_PORT_ROLE_FCP_TARGET)
1848 rport->scsi_target_id = fc_host->next_target_id++; 2412 rport->scsi_target_id = fc_host->next_target_id++;
1849 else 2413 else
1850 rport->scsi_target_id = -1; 2414 rport->scsi_target_id = -1;
@@ -1869,7 +2433,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
1869 transport_add_device(dev); 2433 transport_add_device(dev);
1870 transport_configure_device(dev); 2434 transport_configure_device(dev);
1871 2435
1872 if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) { 2436 if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
1873 /* initiate a scan of the target */ 2437 /* initiate a scan of the target */
1874 rport->flags |= FC_RPORT_SCAN_PENDING; 2438 rport->flags |= FC_RPORT_SCAN_PENDING;
1875 scsi_queue_work(shost, &rport->scan_work); 2439 scsi_queue_work(shost, &rport->scan_work);
@@ -2003,7 +2567,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
2003 2567
2004 /* was a target, not in roles */ 2568 /* was a target, not in roles */
2005 if ((rport->scsi_target_id != -1) && 2569 if ((rport->scsi_target_id != -1) &&
2006 (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET))) 2570 (!(ids->roles & FC_PORT_ROLE_FCP_TARGET)))
2007 return rport; 2571 return rport;
2008 2572
2009 /* 2573 /*
@@ -2086,7 +2650,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
2086 memset(rport->dd_data, 0, 2650 memset(rport->dd_data, 0,
2087 fci->f->dd_fcrport_size); 2651 fci->f->dd_fcrport_size);
2088 2652
2089 if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) { 2653 if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
2090 /* initiate a scan of the target */ 2654 /* initiate a scan of the target */
2091 rport->flags |= FC_RPORT_SCAN_PENDING; 2655 rport->flags |= FC_RPORT_SCAN_PENDING;
2092 scsi_queue_work(shost, &rport->scan_work); 2656 scsi_queue_work(shost, &rport->scan_work);
@@ -2243,11 +2807,11 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
2243 int create = 0; 2807 int create = 0;
2244 2808
2245 spin_lock_irqsave(shost->host_lock, flags); 2809 spin_lock_irqsave(shost->host_lock, flags);
2246 if (roles & FC_RPORT_ROLE_FCP_TARGET) { 2810 if (roles & FC_PORT_ROLE_FCP_TARGET) {
2247 if (rport->scsi_target_id == -1) { 2811 if (rport->scsi_target_id == -1) {
2248 rport->scsi_target_id = fc_host->next_target_id++; 2812 rport->scsi_target_id = fc_host->next_target_id++;
2249 create = 1; 2813 create = 1;
2250 } else if (!(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) 2814 } else if (!(rport->roles & FC_PORT_ROLE_FCP_TARGET))
2251 create = 1; 2815 create = 1;
2252 } 2816 }
2253 2817
@@ -2317,7 +2881,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
2317 */ 2881 */
2318 if ((rport->port_state == FC_PORTSTATE_ONLINE) && 2882 if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
2319 (rport->scsi_target_id != -1) && 2883 (rport->scsi_target_id != -1) &&
2320 !(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { 2884 !(rport->roles & FC_PORT_ROLE_FCP_TARGET)) {
2321 dev_printk(KERN_ERR, &rport->dev, 2885 dev_printk(KERN_ERR, &rport->dev,
2322 "blocked FC remote port time out: no longer" 2886 "blocked FC remote port time out: no longer"
2323 " a FCP target, removing starget\n"); 2887 " a FCP target, removing starget\n");
@@ -2367,7 +2931,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
2367 */ 2931 */
2368 rport->maxframe_size = -1; 2932 rport->maxframe_size = -1;
2369 rport->supported_classes = FC_COS_UNSPECIFIED; 2933 rport->supported_classes = FC_COS_UNSPECIFIED;
2370 rport->roles = FC_RPORT_ROLE_UNKNOWN; 2934 rport->roles = FC_PORT_ROLE_UNKNOWN;
2371 rport->port_state = FC_PORTSTATE_NOTPRESENT; 2935 rport->port_state = FC_PORTSTATE_NOTPRESENT;
2372 2936
2373 /* remove the identifiers that aren't used in the consisting binding */ 2937 /* remove the identifiers that aren't used in the consisting binding */
@@ -2436,7 +3000,7 @@ fc_scsi_scan_rport(struct work_struct *work)
2436 unsigned long flags; 3000 unsigned long flags;
2437 3001
2438 if ((rport->port_state == FC_PORTSTATE_ONLINE) && 3002 if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
2439 (rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { 3003 (rport->roles & FC_PORT_ROLE_FCP_TARGET)) {
2440 scsi_scan_target(&rport->dev, rport->channel, 3004 scsi_scan_target(&rport->dev, rport->channel,
2441 rport->scsi_target_id, SCAN_WILD_CARD, 1); 3005 rport->scsi_target_id, SCAN_WILD_CARD, 1);
2442 } 3006 }
@@ -2447,6 +3011,203 @@ fc_scsi_scan_rport(struct work_struct *work)
2447} 3011}
2448 3012
2449 3013
3014/**
3015 * fc_vport_create - allocates and creates a FC virtual port.
3016 * @shost: scsi host the virtual port is connected to.
3017 * @channel: Channel on shost port connected to.
3018 * @pdev: parent device for vport
3019 * @ids: The world wide names, FC4 port roles, etc for
3020 * the virtual port.
3021 * @ret_vport: The pointer to the created vport.
3022 *
3023 * Allocates and creates the vport structure, calls the parent host
3024 * to instantiate the vport, the completes w/ class and sysfs creation.
3025 *
3026 * Notes:
3027 * This routine assumes no locks are held on entry.
3028 **/
3029static int
3030fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev,
3031 struct fc_vport_identifiers *ids, struct fc_vport **ret_vport)
3032{
3033 struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
3034 struct fc_internal *fci = to_fc_internal(shost->transportt);
3035 struct fc_vport *vport;
3036 struct device *dev;
3037 unsigned long flags;
3038 size_t size;
3039 int error;
3040
3041 *ret_vport = NULL;
3042
3043 if ( ! fci->f->vport_create)
3044 return -ENOENT;
3045
3046 size = (sizeof(struct fc_vport) + fci->f->dd_fcvport_size);
3047 vport = kzalloc(size, GFP_KERNEL);
3048 if (unlikely(!vport)) {
3049 printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
3050 return -ENOMEM;
3051 }
3052
3053 vport->vport_state = FC_VPORT_UNKNOWN;
3054 vport->vport_last_state = FC_VPORT_UNKNOWN;
3055 vport->node_name = ids->node_name;
3056 vport->port_name = ids->port_name;
3057 vport->roles = ids->roles;
3058 vport->vport_type = ids->vport_type;
3059 if (fci->f->dd_fcvport_size)
3060 vport->dd_data = &vport[1];
3061 vport->shost = shost;
3062 vport->channel = channel;
3063 vport->flags = FC_VPORT_CREATING;
3064
3065 spin_lock_irqsave(shost->host_lock, flags);
3066
3067 if (fc_host->npiv_vports_inuse >= fc_host->max_npiv_vports) {
3068 spin_unlock_irqrestore(shost->host_lock, flags);
3069 kfree(vport);
3070 return -ENOSPC;
3071 }
3072 fc_host->npiv_vports_inuse++;
3073 vport->number = fc_host->next_vport_number++;
3074 list_add_tail(&vport->peers, &fc_host->vports);
3075 get_device(&shost->shost_gendev); /* for fc_host->vport list */
3076
3077 spin_unlock_irqrestore(shost->host_lock, flags);
3078
3079 dev = &vport->dev;
3080 device_initialize(dev); /* takes self reference */
3081 dev->parent = get_device(pdev); /* takes parent reference */
3082 dev->release = fc_vport_dev_release;
3083 sprintf(dev->bus_id, "vport-%d:%d-%d",
3084 shost->host_no, channel, vport->number);
3085 transport_setup_device(dev);
3086
3087 error = device_add(dev);
3088 if (error) {
3089 printk(KERN_ERR "FC Virtual Port device_add failed\n");
3090 goto delete_vport;
3091 }
3092 transport_add_device(dev);
3093 transport_configure_device(dev);
3094
3095 error = fci->f->vport_create(vport, ids->disable);
3096 if (error) {
3097 printk(KERN_ERR "FC Virtual Port LLDD Create failed\n");
3098 goto delete_vport_all;
3099 }
3100
3101 /*
3102 * if the parent isn't the physical adapter's Scsi_Host, ensure
3103 * the Scsi_Host at least contains ia symlink to the vport.
3104 */
3105 if (pdev != &shost->shost_gendev) {
3106 error = sysfs_create_link(&shost->shost_gendev.kobj,
3107 &dev->kobj, dev->bus_id);
3108 if (error)
3109 printk(KERN_ERR
3110 "%s: Cannot create vport symlinks for "
3111 "%s, err=%d\n",
3112 __FUNCTION__, dev->bus_id, error);
3113 }
3114 spin_lock_irqsave(shost->host_lock, flags);
3115 vport->flags &= ~FC_VPORT_CREATING;
3116 spin_unlock_irqrestore(shost->host_lock, flags);
3117
3118 dev_printk(KERN_NOTICE, pdev,
3119 "%s created via shost%d channel %d\n", dev->bus_id,
3120 shost->host_no, channel);
3121
3122 *ret_vport = vport;
3123
3124 return 0;
3125
3126delete_vport_all:
3127 transport_remove_device(dev);
3128 device_del(dev);
3129delete_vport:
3130 transport_destroy_device(dev);
3131 spin_lock_irqsave(shost->host_lock, flags);
3132 list_del(&vport->peers);
3133 put_device(&shost->shost_gendev); /* for fc_host->vport list */
3134 fc_host->npiv_vports_inuse--;
3135 spin_unlock_irqrestore(shost->host_lock, flags);
3136 put_device(dev->parent);
3137 kfree(vport);
3138
3139 return error;
3140}
3141
3142
3143/**
3144 * fc_vport_terminate - Admin App or LLDD requests termination of a vport
3145 * @vport: fc_vport to be terminated
3146 *
3147 * Calls the LLDD vport_delete() function, then deallocates and removes
3148 * the vport from the shost and object tree.
3149 *
3150 * Notes:
3151 * This routine assumes no locks are held on entry.
3152 **/
3153int
3154fc_vport_terminate(struct fc_vport *vport)
3155{
3156 struct Scsi_Host *shost = vport_to_shost(vport);
3157 struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
3158 struct fc_internal *i = to_fc_internal(shost->transportt);
3159 struct device *dev = &vport->dev;
3160 unsigned long flags;
3161 int stat;
3162
3163 spin_lock_irqsave(shost->host_lock, flags);
3164 if (vport->flags & FC_VPORT_CREATING) {
3165 spin_unlock_irqrestore(shost->host_lock, flags);
3166 return -EBUSY;
3167 }
3168 if (vport->flags & (FC_VPORT_DEL)) {
3169 spin_unlock_irqrestore(shost->host_lock, flags);
3170 return -EALREADY;
3171 }
3172 vport->flags |= FC_VPORT_DELETING;
3173 spin_unlock_irqrestore(shost->host_lock, flags);
3174
3175 if (i->f->vport_delete)
3176 stat = i->f->vport_delete(vport);
3177 else
3178 stat = -ENOENT;
3179
3180 spin_lock_irqsave(shost->host_lock, flags);
3181 vport->flags &= ~FC_VPORT_DELETING;
3182 if (!stat) {
3183 vport->flags |= FC_VPORT_DELETED;
3184 list_del(&vport->peers);
3185 fc_host->npiv_vports_inuse--;
3186 put_device(&shost->shost_gendev); /* for fc_host->vport list */
3187 }
3188 spin_unlock_irqrestore(shost->host_lock, flags);
3189
3190 if (stat)
3191 return stat;
3192
3193 if (dev->parent != &shost->shost_gendev)
3194 sysfs_remove_link(&shost->shost_gendev.kobj, dev->bus_id);
3195 transport_remove_device(dev);
3196 device_del(dev);
3197 transport_destroy_device(dev);
3198
3199 /*
3200 * Removing our self-reference should mean our
3201 * release function gets called, which will drop the remaining
3202 * parent reference and free the data structure.
3203 */
3204 put_device(dev); /* for self-reference */
3205
3206 return 0; /* SUCCESS */
3207}
3208EXPORT_SYMBOL(fc_vport_terminate);
3209
3210
2450MODULE_AUTHOR("Martin Hicks"); 3211MODULE_AUTHOR("Martin Hicks");
2451MODULE_DESCRIPTION("FC Transport Attributes"); 3212MODULE_DESCRIPTION("FC Transport Attributes");
2452MODULE_LICENSE("GPL"); 3213MODULE_LICENSE("GPL");
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index 1e797308640a..81ea7b4bf81e 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -19,7 +19,7 @@
19 * 19 *
20 * ======== 20 * ========
21 * 21 *
22 * Copyright (C) 2004-2005 James Smart, Emulex Corporation 22 * Copyright (C) 2004-2007 James Smart, Emulex Corporation
23 * Rewrite for host, target, device, and remote port attributes, 23 * Rewrite for host, target, device, and remote port attributes,
24 * statistics, and service functions... 24 * statistics, and service functions...
25 * 25 *
@@ -62,8 +62,10 @@ enum fc_port_type {
62 FC_PORTTYPE_NLPORT, /* (Public) Loop w/ FLPort */ 62 FC_PORTTYPE_NLPORT, /* (Public) Loop w/ FLPort */
63 FC_PORTTYPE_LPORT, /* (Private) Loop w/o FLPort */ 63 FC_PORTTYPE_LPORT, /* (Private) Loop w/o FLPort */
64 FC_PORTTYPE_PTP, /* Point to Point w/ another NPort */ 64 FC_PORTTYPE_PTP, /* Point to Point w/ another NPort */
65 FC_PORTTYPE_NPIV, /* VPORT based on NPIV */
65}; 66};
66 67
68
67/* 69/*
68 * fc_port_state: If you alter this, you also need to alter scsi_transport_fc.c 70 * fc_port_state: If you alter this, you also need to alter scsi_transport_fc.c
69 * (for the ascii descriptions). 71 * (for the ascii descriptions).
@@ -83,6 +85,25 @@ enum fc_port_state {
83}; 85};
84 86
85 87
88/*
89 * fc_vport_state: If you alter this, you also need to alter
90 * scsi_transport_fc.c (for the ascii descriptions).
91 */
92enum fc_vport_state {
93 FC_VPORT_UNKNOWN,
94 FC_VPORT_ACTIVE,
95 FC_VPORT_DISABLED,
96 FC_VPORT_LINKDOWN,
97 FC_VPORT_INITIALIZING,
98 FC_VPORT_NO_FABRIC_SUPP,
99 FC_VPORT_NO_FABRIC_RSCS,
100 FC_VPORT_FABRIC_LOGOUT,
101 FC_VPORT_FABRIC_REJ_WWN,
102 FC_VPORT_FAILED,
103};
104
105
106
86/* 107/*
87 * FC Classes of Service 108 * FC Classes of Service
88 * Note: values are not enumerated, as they can be "or'd" together 109 * Note: values are not enumerated, as they can be "or'd" together
@@ -124,18 +145,115 @@ enum fc_tgtid_binding_type {
124}; 145};
125 146
126/* 147/*
127 * FC Remote Port Roles 148 * FC Port Roles
128 * Note: values are not enumerated, as they can be "or'd" together 149 * Note: values are not enumerated, as they can be "or'd" together
129 * for reporting (e.g. report roles). If you alter this list, 150 * for reporting (e.g. report roles). If you alter this list,
130 * you also need to alter scsi_transport_fc.c (for the ascii descriptions). 151 * you also need to alter scsi_transport_fc.c (for the ascii descriptions).
131 */ 152 */
132#define FC_RPORT_ROLE_UNKNOWN 0x00 153#define FC_PORT_ROLE_UNKNOWN 0x00
133#define FC_RPORT_ROLE_FCP_TARGET 0x01 154#define FC_PORT_ROLE_FCP_TARGET 0x01
134#define FC_RPORT_ROLE_FCP_INITIATOR 0x02 155#define FC_PORT_ROLE_FCP_INITIATOR 0x02
135#define FC_RPORT_ROLE_IP_PORT 0x04 156#define FC_PORT_ROLE_IP_PORT 0x04
157
158/* The following are for compatibility */
159#define FC_RPORT_ROLE_UNKNOWN FC_PORT_ROLE_UNKNOWN
160#define FC_RPORT_ROLE_FCP_TARGET FC_PORT_ROLE_FCP_TARGET
161#define FC_RPORT_ROLE_FCP_INITIATOR FC_PORT_ROLE_FCP_INITIATOR
162#define FC_RPORT_ROLE_IP_PORT FC_PORT_ROLE_IP_PORT
163
164
165/* Macro for use in defining Virtual Port attributes */
166#define FC_VPORT_ATTR(_name,_mode,_show,_store) \
167struct class_device_attribute class_device_attr_vport_##_name = \
168 __ATTR(_name,_mode,_show,_store)
136 169
137 170
138/* 171/*
172 * FC Virtual Port Attributes
173 *
174 * This structure exists for each FC port is a virtual FC port. Virtual
175 * ports share the physical link with the Physical port. Each virtual
176 * ports has a unique presense on the SAN, and may be instantiated via
177 * NPIV, Virtual Fabrics, or via additional ALPAs. As the vport is a
178 * unique presense, each vport has it's own view of the fabric,
179 * authentication priviledge, and priorities.
180 *
181 * A virtual port may support 1 or more FC4 roles. Typically it is a
182 * FCP Initiator. It could be a FCP Target, or exist sole for an IP over FC
183 * roles. FC port attributes for the vport will be reported on any
184 * fc_host class object allocated for an FCP Initiator.
185 *
186 * --
187 *
188 * Fixed attributes are not expected to change. The driver is
189 * expected to set these values after receiving the fc_vport structure
190 * via the vport_create() call from the transport.
191 * The transport fully manages all get functions w/o driver interaction.
192 *
193 * Dynamic attributes are expected to change. The driver participates
194 * in all get/set operations via functions provided by the driver.
195 *
196 * Private attributes are transport-managed values. They are fully
197 * managed by the transport w/o driver interaction.
198 */
199
200#define FC_VPORT_SYMBOLIC_NAMELEN 64
201struct fc_vport {
202 /* Fixed Attributes */
203
204 /* Dynamic Attributes */
205
206 /* Private (Transport-managed) Attributes */
207 enum fc_vport_state vport_state;
208 enum fc_vport_state vport_last_state;
209 u64 node_name;
210 u64 port_name;
211 u32 roles;
212 u32 vport_id; /* Admin Identifier for the vport */
213 enum fc_port_type vport_type;
214 char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];
215
216 /* exported data */
217 void *dd_data; /* Used for driver-specific storage */
218
219 /* internal data */
220 struct Scsi_Host *shost; /* Physical Port Parent */
221 unsigned int channel;
222 u32 number;
223 u8 flags;
224 struct list_head peers;
225 struct device dev;
226} __attribute__((aligned(sizeof(unsigned long))));
227
228/* bit field values for struct fc_vport "flags" field: */
229#define FC_VPORT_CREATING 0x01
230#define FC_VPORT_DELETING 0x02
231#define FC_VPORT_DELETED 0x04
232#define FC_VPORT_DEL 0x06 /* Any DELETE state */
233
234#define dev_to_vport(d) \
235 container_of(d, struct fc_vport, dev)
236#define transport_class_to_vport(classdev) \
237 dev_to_vport(classdev->dev)
238#define vport_to_shost(v) \
239 (v->shost)
240#define vport_to_shost_channel(v) \
241 (v->channel)
242#define vport_to_parent(v) \
243 (v->dev.parent)
244
245
246/* Error return codes for vport_create() callback */
247#define VPCERR_UNSUPPORTED -ENOSYS /* no driver/adapter
248 support */
249#define VPCERR_BAD_WWN -ENOTUNIQ /* driver validation
250 of WWNs failed */
251#define VPCERR_NO_FABRIC_SUPP -EOPNOTSUPP /* Fabric connection
252 is loop or the
253 Fabric Port does
254 not support NPIV */
255
256/*
139 * fc_rport_identifiers: This set of data contains all elements 257 * fc_rport_identifiers: This set of data contains all elements
140 * to uniquely identify a remote FC port. The driver uses this data 258 * to uniquely identify a remote FC port. The driver uses this data
141 * to report the existence of a remote FC port in the topology. Internally, 259 * to report the existence of a remote FC port in the topology. Internally,
@@ -149,6 +267,7 @@ struct fc_rport_identifiers {
149 u32 roles; 267 u32 roles;
150}; 268};
151 269
270
152/* Macro for use in defining Remote Port attributes */ 271/* Macro for use in defining Remote Port attributes */
153#define FC_RPORT_ATTR(_name,_mode,_show,_store) \ 272#define FC_RPORT_ATTR(_name,_mode,_show,_store) \
154struct class_device_attribute class_device_attr_rport_##_name = \ 273struct class_device_attribute class_device_attr_rport_##_name = \
@@ -343,6 +462,7 @@ struct fc_host_attrs {
343 u8 supported_fc4s[FC_FC4_LIST_SIZE]; 462 u8 supported_fc4s[FC_FC4_LIST_SIZE];
344 u32 supported_speeds; 463 u32 supported_speeds;
345 u32 maxframe_size; 464 u32 maxframe_size;
465 u16 max_npiv_vports;
346 char serial_number[FC_SERIAL_NUMBER_SIZE]; 466 char serial_number[FC_SERIAL_NUMBER_SIZE];
347 467
348 /* Dynamic Attributes */ 468 /* Dynamic Attributes */
@@ -361,8 +481,11 @@ struct fc_host_attrs {
361 /* internal data */ 481 /* internal data */
362 struct list_head rports; 482 struct list_head rports;
363 struct list_head rport_bindings; 483 struct list_head rport_bindings;
484 struct list_head vports;
364 u32 next_rport_number; 485 u32 next_rport_number;
365 u32 next_target_id; 486 u32 next_target_id;
487 u32 next_vport_number;
488 u16 npiv_vports_inuse;
366 489
367 /* work queues for rport state manipulation */ 490 /* work queues for rport state manipulation */
368 char work_q_name[KOBJ_NAME_LEN]; 491 char work_q_name[KOBJ_NAME_LEN];
@@ -388,6 +511,8 @@ struct fc_host_attrs {
388 (((struct fc_host_attrs *)(x)->shost_data)->supported_speeds) 511 (((struct fc_host_attrs *)(x)->shost_data)->supported_speeds)
389#define fc_host_maxframe_size(x) \ 512#define fc_host_maxframe_size(x) \
390 (((struct fc_host_attrs *)(x)->shost_data)->maxframe_size) 513 (((struct fc_host_attrs *)(x)->shost_data)->maxframe_size)
514#define fc_host_max_npiv_vports(x) \
515 (((struct fc_host_attrs *)(x)->shost_data)->max_npiv_vports)
391#define fc_host_serial_number(x) \ 516#define fc_host_serial_number(x) \
392 (((struct fc_host_attrs *)(x)->shost_data)->serial_number) 517 (((struct fc_host_attrs *)(x)->shost_data)->serial_number)
393#define fc_host_port_id(x) \ 518#define fc_host_port_id(x) \
@@ -412,10 +537,16 @@ struct fc_host_attrs {
412 (((struct fc_host_attrs *)(x)->shost_data)->rports) 537 (((struct fc_host_attrs *)(x)->shost_data)->rports)
413#define fc_host_rport_bindings(x) \ 538#define fc_host_rport_bindings(x) \
414 (((struct fc_host_attrs *)(x)->shost_data)->rport_bindings) 539 (((struct fc_host_attrs *)(x)->shost_data)->rport_bindings)
540#define fc_host_vports(x) \
541 (((struct fc_host_attrs *)(x)->shost_data)->vports)
415#define fc_host_next_rport_number(x) \ 542#define fc_host_next_rport_number(x) \
416 (((struct fc_host_attrs *)(x)->shost_data)->next_rport_number) 543 (((struct fc_host_attrs *)(x)->shost_data)->next_rport_number)
417#define fc_host_next_target_id(x) \ 544#define fc_host_next_target_id(x) \
418 (((struct fc_host_attrs *)(x)->shost_data)->next_target_id) 545 (((struct fc_host_attrs *)(x)->shost_data)->next_target_id)
546#define fc_host_next_vport_number(x) \
547 (((struct fc_host_attrs *)(x)->shost_data)->next_vport_number)
548#define fc_host_npiv_vports_inuse(x) \
549 (((struct fc_host_attrs *)(x)->shost_data)->npiv_vports_inuse)
419#define fc_host_work_q_name(x) \ 550#define fc_host_work_q_name(x) \
420 (((struct fc_host_attrs *)(x)->shost_data)->work_q_name) 551 (((struct fc_host_attrs *)(x)->shost_data)->work_q_name)
421#define fc_host_work_q(x) \ 552#define fc_host_work_q(x) \
@@ -452,8 +583,14 @@ struct fc_function_template {
452 void (*dev_loss_tmo_callbk)(struct fc_rport *); 583 void (*dev_loss_tmo_callbk)(struct fc_rport *);
453 void (*terminate_rport_io)(struct fc_rport *); 584 void (*terminate_rport_io)(struct fc_rport *);
454 585
586 void (*set_vport_symbolic_name)(struct fc_vport *);
587 int (*vport_create)(struct fc_vport *, bool);
588 int (*vport_disable)(struct fc_vport *, bool);
589 int (*vport_delete)(struct fc_vport *);
590
455 /* allocation lengths for host-specific data */ 591 /* allocation lengths for host-specific data */
456 u32 dd_fcrport_size; 592 u32 dd_fcrport_size;
593 u32 dd_fcvport_size;
457 594
458 /* 595 /*
459 * The driver sets these to tell the transport class it 596 * The driver sets these to tell the transport class it
@@ -512,7 +649,7 @@ fc_remote_port_chkready(struct fc_rport *rport)
512 649
513 switch (rport->port_state) { 650 switch (rport->port_state) {
514 case FC_PORTSTATE_ONLINE: 651 case FC_PORTSTATE_ONLINE:
515 if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) 652 if (rport->roles & FC_PORT_ROLE_FCP_TARGET)
516 result = 0; 653 result = 0;
517 else if (rport->flags & FC_RPORT_DEVLOSS_PENDING) 654 else if (rport->flags & FC_RPORT_DEVLOSS_PENDING)
518 result = DID_IMM_RETRY << 16; 655 result = DID_IMM_RETRY << 16;
@@ -549,6 +686,27 @@ static inline void u64_to_wwn(u64 inm, u8 *wwn)
549 wwn[7] = inm & 0xff; 686 wwn[7] = inm & 0xff;
550} 687}
551 688
689/**
690 * fc_vport_set_state() - called to set a vport's state. Saves the old state,
691 * excepting the transitory states of initializing and sending the ELS
692 * traffic to instantiate the vport on the link.
693 *
694 * Assumes the driver has surrounded this with the proper locking to ensure
695 * a coherent state change.
696 *
697 * @vport: virtual port whose state is changing
698 * @new_state: new state
699 **/
700static inline void
701fc_vport_set_state(struct fc_vport *vport, enum fc_vport_state new_state)
702{
703 if ((new_state != FC_VPORT_UNKNOWN) &&
704 (new_state != FC_VPORT_INITIALIZING))
705 vport->vport_last_state = vport->vport_state;
706 vport->vport_state = new_state;
707}
708
709
552struct scsi_transport_template *fc_attach_transport( 710struct scsi_transport_template *fc_attach_transport(
553 struct fc_function_template *); 711 struct fc_function_template *);
554void fc_release_transport(struct scsi_transport_template *); 712void fc_release_transport(struct scsi_transport_template *);
@@ -567,5 +725,6 @@ void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
567 * be sure to read the Vendor Type and ID formatting requirements 725 * be sure to read the Vendor Type and ID formatting requirements
568 * specified in scsi_netlink.h 726 * specified in scsi_netlink.h
569 */ 727 */
728int fc_vport_terminate(struct fc_vport *vport);
570 729
571#endif /* SCSI_TRANSPORT_FC_H */ 730#endif /* SCSI_TRANSPORT_FC_H */