1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * Copyright(c) 2008 Intel Corporation. All rights reserved. |
4 | * |
5 | * Maintained at www.Open-FCoE.org |
6 | */ |
7 | |
8 | #ifndef _FC_ENCODE_H_ |
9 | #define _FC_ENCODE_H_ |
10 | #include <asm/unaligned.h> |
11 | #include <linux/utsname.h> |
12 | #include <scsi/fc/fc_ms.h> |
13 | |
14 | /* |
15 | * F_CTL values for simple requests and responses. |
16 | */ |
17 | #define FC_FCTL_REQ (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT) |
18 | #define FC_FCTL_RESP (FC_FC_EX_CTX | FC_FC_LAST_SEQ | \ |
19 | FC_FC_END_SEQ | FC_FC_SEQ_INIT) |
20 | |
21 | struct fc_ns_rft { |
22 | struct fc_ns_fid fid; /* port ID object */ |
23 | struct fc_ns_fts fts; /* FC4-types object */ |
24 | }; |
25 | |
26 | struct fc_ct_req { |
27 | struct fc_ct_hdr hdr; |
28 | union { |
29 | struct fc_ns_gid_ft gid; |
30 | struct fc_ns_rn_id rn; |
31 | struct fc_ns_rft rft; |
32 | struct fc_ns_rff_id rff; |
33 | struct fc_ns_fid fid; |
34 | struct fc_ns_rsnn snn; |
35 | struct fc_ns_rspn spn; |
36 | struct fc_fdmi_rhba rhba; |
37 | struct fc_fdmi_rpa rpa; |
38 | struct fc_fdmi_dprt dprt; |
39 | struct fc_fdmi_dhba dhba; |
40 | } payload; |
41 | }; |
42 | |
43 | /** |
44 | * fc_adisc_fill() - Fill in adisc request frame |
45 | * @lport: local port. |
46 | * @fp: fc frame where payload will be placed. |
47 | */ |
48 | static inline void fc_adisc_fill(struct fc_lport *lport, struct fc_frame *fp) |
49 | { |
50 | struct fc_els_adisc *adisc; |
51 | |
52 | adisc = fc_frame_payload_get(fp, len: sizeof(*adisc)); |
53 | memset(adisc, 0, sizeof(*adisc)); |
54 | adisc->adisc_cmd = ELS_ADISC; |
55 | put_unaligned_be64(val: lport->wwpn, p: &adisc->adisc_wwpn); |
56 | put_unaligned_be64(val: lport->wwnn, p: &adisc->adisc_wwnn); |
57 | hton24(p: adisc->adisc_port_id, v: lport->port_id); |
58 | } |
59 | |
60 | /** |
61 | * fc_ct_hdr_fill- fills ct header and reset ct payload |
62 | * returns pointer to ct request. |
63 | */ |
64 | static inline struct fc_ct_req *fc_ct_hdr_fill(const struct fc_frame *fp, |
65 | unsigned int op, size_t req_size, |
66 | enum fc_ct_fs_type fs_type, |
67 | u8 subtype) |
68 | { |
69 | struct fc_ct_req *ct; |
70 | size_t ct_plen; |
71 | |
72 | ct_plen = sizeof(struct fc_ct_hdr) + req_size; |
73 | ct = fc_frame_payload_get(fp, len: ct_plen); |
74 | memset(ct, 0, ct_plen); |
75 | ct->hdr.ct_rev = FC_CT_REV; |
76 | ct->hdr.ct_fs_type = fs_type; |
77 | ct->hdr.ct_fs_subtype = subtype; |
78 | ct->hdr.ct_cmd = htons((u16) op); |
79 | return ct; |
80 | } |
81 | |
82 | /** |
83 | * fc_ct_ns_fill() - Fill in a name service request frame |
84 | * @lport: local port. |
85 | * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries. |
86 | * @fp: frame to contain payload. |
87 | * @op: CT opcode. |
88 | * @r_ctl: pointer to FC header R_CTL. |
89 | * @fh_type: pointer to FC-4 type. |
90 | */ |
91 | static inline int fc_ct_ns_fill(struct fc_lport *lport, |
92 | u32 fc_id, struct fc_frame *fp, |
93 | unsigned int op, enum fc_rctl *r_ctl, |
94 | enum fc_fh_type *fh_type) |
95 | { |
96 | struct fc_ct_req *ct; |
97 | size_t len; |
98 | |
99 | switch (op) { |
100 | case FC_NS_GPN_FT: |
101 | ct = fc_ct_hdr_fill(fp, op, req_size: sizeof(struct fc_ns_gid_ft), |
102 | fs_type: FC_FST_DIR, FC_NS_SUBTYPE); |
103 | ct->payload.gid.fn_fc4_type = FC_TYPE_FCP; |
104 | break; |
105 | |
106 | case FC_NS_GPN_ID: |
107 | ct = fc_ct_hdr_fill(fp, op, req_size: sizeof(struct fc_ns_fid), |
108 | fs_type: FC_FST_DIR, FC_NS_SUBTYPE); |
109 | ct->payload.gid.fn_fc4_type = FC_TYPE_FCP; |
110 | hton24(p: ct->payload.fid.fp_fid, v: fc_id); |
111 | break; |
112 | |
113 | case FC_NS_RFT_ID: |
114 | ct = fc_ct_hdr_fill(fp, op, req_size: sizeof(struct fc_ns_rft), |
115 | fs_type: FC_FST_DIR, FC_NS_SUBTYPE); |
116 | hton24(p: ct->payload.rft.fid.fp_fid, v: lport->port_id); |
117 | ct->payload.rft.fts = lport->fcts; |
118 | break; |
119 | |
120 | case FC_NS_RFF_ID: |
121 | ct = fc_ct_hdr_fill(fp, op, req_size: sizeof(struct fc_ns_rff_id), |
122 | fs_type: FC_FST_DIR, FC_NS_SUBTYPE); |
123 | hton24(p: ct->payload.rff.fr_fid.fp_fid, v: lport->port_id); |
124 | ct->payload.rff.fr_type = FC_TYPE_FCP; |
125 | if (lport->service_params & FCP_SPPF_INIT_FCN) |
126 | ct->payload.rff.fr_feat = FCP_FEAT_INIT; |
127 | if (lport->service_params & FCP_SPPF_TARG_FCN) |
128 | ct->payload.rff.fr_feat |= FCP_FEAT_TARG; |
129 | break; |
130 | |
131 | case FC_NS_RNN_ID: |
132 | ct = fc_ct_hdr_fill(fp, op, req_size: sizeof(struct fc_ns_rn_id), |
133 | fs_type: FC_FST_DIR, FC_NS_SUBTYPE); |
134 | hton24(p: ct->payload.rn.fr_fid.fp_fid, v: lport->port_id); |
135 | put_unaligned_be64(val: lport->wwnn, p: &ct->payload.rn.fr_wwn); |
136 | break; |
137 | |
138 | case FC_NS_RSPN_ID: |
139 | len = strnlen(fc_host_symbolic_name(lport->host), |
140 | FC_SYMBOLIC_NAME_SIZE); |
141 | ct = fc_ct_hdr_fill(fp, op, req_size: sizeof(struct fc_ns_rspn) + len, |
142 | fs_type: FC_FST_DIR, FC_NS_SUBTYPE); |
143 | hton24(p: ct->payload.spn.fr_fid.fp_fid, v: lport->port_id); |
144 | memcpy(ct->payload.spn.fr_name, |
145 | fc_host_symbolic_name(lport->host), len); |
146 | ct->payload.spn.fr_name_len = len; |
147 | break; |
148 | |
149 | case FC_NS_RSNN_NN: |
150 | len = strnlen(fc_host_symbolic_name(lport->host), |
151 | FC_SYMBOLIC_NAME_SIZE); |
152 | ct = fc_ct_hdr_fill(fp, op, req_size: sizeof(struct fc_ns_rsnn) + len, |
153 | fs_type: FC_FST_DIR, FC_NS_SUBTYPE); |
154 | put_unaligned_be64(val: lport->wwnn, p: &ct->payload.snn.fr_wwn); |
155 | memcpy(ct->payload.snn.fr_name, |
156 | fc_host_symbolic_name(lport->host), len); |
157 | ct->payload.snn.fr_name_len = len; |
158 | break; |
159 | |
160 | default: |
161 | return -EINVAL; |
162 | } |
163 | *r_ctl = FC_RCTL_DD_UNSOL_CTL; |
164 | *fh_type = FC_TYPE_CT; |
165 | return 0; |
166 | } |
167 | |
168 | static inline void fc_ct_ms_fill_attr(struct fc_fdmi_attr_entry *entry, |
169 | const char *in, size_t len) |
170 | { |
171 | int copied; |
172 | |
173 | copied = strscpy(entry->value, in, len); |
174 | if (copied > 0 && copied + 1 < len) |
175 | memset(entry->value + copied + 1, 0, len - copied - 1); |
176 | } |
177 | |
178 | /** |
179 | * fc_ct_ms_fill() - Fill in a mgmt service request frame |
180 | * @lport: local port. |
181 | * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries. |
182 | * @fp: frame to contain payload. |
183 | * @op: CT opcode. |
184 | * @r_ctl: pointer to FC header R_CTL. |
185 | * @fh_type: pointer to FC-4 type. |
186 | */ |
187 | static inline int fc_ct_ms_fill(struct fc_lport *lport, |
188 | u32 fc_id, struct fc_frame *fp, |
189 | unsigned int op, enum fc_rctl *r_ctl, |
190 | enum fc_fh_type *fh_type) |
191 | { |
192 | struct fc_ct_req *ct; |
193 | size_t len; |
194 | struct fc_fdmi_attr_entry *entry; |
195 | struct fs_fdmi_attrs *hba_attrs; |
196 | int numattrs = 0; |
197 | struct fc_host_attrs *fc_host = shost_to_fc_host(lport->host); |
198 | |
199 | switch (op) { |
200 | case FC_FDMI_RHBA: |
201 | numattrs = 11; |
202 | len = sizeof(struct fc_fdmi_rhba); |
203 | len -= sizeof(struct fc_fdmi_attr_entry); |
204 | len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN); |
205 | len += FC_FDMI_HBA_ATTR_NODENAME_LEN; |
206 | len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN; |
207 | len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN; |
208 | len += FC_FDMI_HBA_ATTR_MODEL_LEN; |
209 | len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN; |
210 | len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN; |
211 | len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN; |
212 | len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN; |
213 | len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN; |
214 | len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN; |
215 | len += FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN; |
216 | |
217 | if (fc_host->fdmi_version == FDMI_V2) { |
218 | numattrs += 7; |
219 | len += FC_FDMI_HBA_ATTR_NODESYMBLNAME_LEN; |
220 | len += FC_FDMI_HBA_ATTR_VENDORSPECIFICINFO_LEN; |
221 | len += FC_FDMI_HBA_ATTR_NUMBEROFPORTS_LEN; |
222 | len += FC_FDMI_HBA_ATTR_FABRICNAME_LEN; |
223 | len += FC_FDMI_HBA_ATTR_BIOSVERSION_LEN; |
224 | len += FC_FDMI_HBA_ATTR_BIOSSTATE_LEN; |
225 | len += FC_FDMI_HBA_ATTR_VENDORIDENTIFIER_LEN; |
226 | } |
227 | |
228 | ct = fc_ct_hdr_fill(fp, op, req_size: len, fs_type: FC_FST_MGMT, |
229 | FC_FDMI_SUBTYPE); |
230 | |
231 | /* HBA Identifier */ |
232 | put_unaligned_be64(val: lport->wwpn, p: &ct->payload.rhba.hbaid.id); |
233 | /* Number of Ports - always 1 */ |
234 | put_unaligned_be32(val: 1, p: &ct->payload.rhba.port.numport); |
235 | /* Port Name */ |
236 | put_unaligned_be64(val: lport->wwpn, |
237 | p: &ct->payload.rhba.port.port[0].portname); |
238 | |
239 | /* HBA Attributes */ |
240 | put_unaligned_be32(val: numattrs, |
241 | p: &ct->payload.rhba.hba_attrs.numattrs); |
242 | hba_attrs = &ct->payload.rhba.hba_attrs; |
243 | entry = (struct fc_fdmi_attr_entry *)hba_attrs->attr; |
244 | /* NodeName*/ |
245 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
246 | len += FC_FDMI_HBA_ATTR_NODENAME_LEN; |
247 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_NODENAME, |
248 | p: &entry->type); |
249 | put_unaligned_be16(val: len, p: &entry->len); |
250 | put_unaligned_be64(val: lport->wwnn, |
251 | p: (__be64 *)&entry->value); |
252 | |
253 | /* Manufacturer */ |
254 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
255 | FC_FDMI_HBA_ATTR_NODENAME_LEN); |
256 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
257 | len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN; |
258 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_MANUFACTURER, |
259 | p: &entry->type); |
260 | put_unaligned_be16(val: len, p: &entry->len); |
261 | fc_ct_ms_fill_attr(entry, |
262 | fc_host_manufacturer(lport->host), |
263 | FC_FDMI_HBA_ATTR_MANUFACTURER_LEN); |
264 | |
265 | /* SerialNumber */ |
266 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
267 | FC_FDMI_HBA_ATTR_MANUFACTURER_LEN); |
268 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
269 | len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN; |
270 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_SERIALNUMBER, |
271 | p: &entry->type); |
272 | put_unaligned_be16(val: len, p: &entry->len); |
273 | fc_ct_ms_fill_attr(entry, |
274 | fc_host_serial_number(lport->host), |
275 | FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN); |
276 | |
277 | /* Model */ |
278 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
279 | FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN); |
280 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
281 | len += FC_FDMI_HBA_ATTR_MODEL_LEN; |
282 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_MODEL, |
283 | p: &entry->type); |
284 | put_unaligned_be16(val: len, p: &entry->len); |
285 | fc_ct_ms_fill_attr(entry, |
286 | fc_host_model(lport->host), |
287 | FC_FDMI_HBA_ATTR_MODEL_LEN); |
288 | |
289 | /* Model Description */ |
290 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
291 | FC_FDMI_HBA_ATTR_MODEL_LEN); |
292 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
293 | len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN; |
294 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_MODELDESCRIPTION, |
295 | p: &entry->type); |
296 | put_unaligned_be16(val: len, p: &entry->len); |
297 | fc_ct_ms_fill_attr(entry, |
298 | fc_host_model_description(lport->host), |
299 | FC_FDMI_HBA_ATTR_MODELDESCR_LEN); |
300 | |
301 | /* Hardware Version */ |
302 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
303 | FC_FDMI_HBA_ATTR_MODELDESCR_LEN); |
304 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
305 | len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN; |
306 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_HARDWAREVERSION, |
307 | p: &entry->type); |
308 | put_unaligned_be16(val: len, p: &entry->len); |
309 | fc_ct_ms_fill_attr(entry, |
310 | fc_host_hardware_version(lport->host), |
311 | FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN); |
312 | |
313 | /* Driver Version */ |
314 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
315 | FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN); |
316 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
317 | len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN; |
318 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_DRIVERVERSION, |
319 | p: &entry->type); |
320 | put_unaligned_be16(val: len, p: &entry->len); |
321 | fc_ct_ms_fill_attr(entry, |
322 | fc_host_driver_version(lport->host), |
323 | FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN); |
324 | |
325 | /* OptionROM Version */ |
326 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
327 | FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN); |
328 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
329 | len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN; |
330 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_OPTIONROMVERSION, |
331 | p: &entry->type); |
332 | put_unaligned_be16(val: len, p: &entry->len); |
333 | fc_ct_ms_fill_attr(entry, |
334 | in: "unknown" , |
335 | FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN); |
336 | |
337 | /* Firmware Version */ |
338 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
339 | FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN); |
340 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
341 | len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN; |
342 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_FIRMWAREVERSION, |
343 | p: &entry->type); |
344 | put_unaligned_be16(val: len, p: &entry->len); |
345 | fc_ct_ms_fill_attr(entry, |
346 | fc_host_firmware_version(lport->host), |
347 | FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN); |
348 | |
349 | /* OS Name and Version */ |
350 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
351 | FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN); |
352 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
353 | len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN; |
354 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_OSNAMEVERSION, |
355 | p: &entry->type); |
356 | put_unaligned_be16(val: len, p: &entry->len); |
357 | snprintf(buf: (char *)&entry->value, |
358 | FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN, |
359 | fmt: "%s v%s" , |
360 | init_utsname()->sysname, |
361 | init_utsname()->release); |
362 | |
363 | /* Max CT payload */ |
364 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
365 | FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN); |
366 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
367 | len += FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN; |
368 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_MAXCTPAYLOAD, |
369 | p: &entry->type); |
370 | put_unaligned_be16(val: len, p: &entry->len); |
371 | put_unaligned_be32(fc_host_max_ct_payload(lport->host), |
372 | p: &entry->value); |
373 | |
374 | if (fc_host->fdmi_version == FDMI_V2) { |
375 | /* Node symbolic name */ |
376 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
377 | FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN); |
378 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
379 | len += FC_FDMI_HBA_ATTR_NODESYMBLNAME_LEN; |
380 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_NODESYMBLNAME, |
381 | p: &entry->type); |
382 | put_unaligned_be16(val: len, p: &entry->len); |
383 | fc_ct_ms_fill_attr(entry, |
384 | fc_host_symbolic_name(lport->host), |
385 | FC_FDMI_HBA_ATTR_NODESYMBLNAME_LEN); |
386 | |
387 | /* Vendor specific info */ |
388 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
389 | FC_FDMI_HBA_ATTR_NODESYMBLNAME_LEN); |
390 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
391 | len += FC_FDMI_HBA_ATTR_VENDORSPECIFICINFO_LEN; |
392 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_VENDORSPECIFICINFO, |
393 | p: &entry->type); |
394 | put_unaligned_be16(val: len, p: &entry->len); |
395 | put_unaligned_be32(val: 0, |
396 | p: &entry->value); |
397 | |
398 | /* Number of ports */ |
399 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
400 | FC_FDMI_HBA_ATTR_VENDORSPECIFICINFO_LEN); |
401 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
402 | len += FC_FDMI_HBA_ATTR_NUMBEROFPORTS_LEN; |
403 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_NUMBEROFPORTS, |
404 | p: &entry->type); |
405 | put_unaligned_be16(val: len, p: &entry->len); |
406 | put_unaligned_be32(fc_host_num_ports(lport->host), |
407 | p: &entry->value); |
408 | |
409 | /* Fabric name */ |
410 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
411 | FC_FDMI_HBA_ATTR_NUMBEROFPORTS_LEN); |
412 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
413 | len += FC_FDMI_HBA_ATTR_FABRICNAME_LEN; |
414 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_FABRICNAME, |
415 | p: &entry->type); |
416 | put_unaligned_be16(val: len, p: &entry->len); |
417 | put_unaligned_be64(fc_host_fabric_name(lport->host), |
418 | p: &entry->value); |
419 | |
420 | /* BIOS version */ |
421 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
422 | FC_FDMI_HBA_ATTR_FABRICNAME_LEN); |
423 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
424 | len += FC_FDMI_HBA_ATTR_BIOSVERSION_LEN; |
425 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_BIOSVERSION, |
426 | p: &entry->type); |
427 | put_unaligned_be16(val: len, p: &entry->len); |
428 | fc_ct_ms_fill_attr(entry, |
429 | fc_host_bootbios_version(lport->host), |
430 | FC_FDMI_HBA_ATTR_BIOSVERSION_LEN); |
431 | |
432 | /* BIOS state */ |
433 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
434 | FC_FDMI_HBA_ATTR_BIOSVERSION_LEN); |
435 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
436 | len += FC_FDMI_HBA_ATTR_BIOSSTATE_LEN; |
437 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_BIOSSTATE, |
438 | p: &entry->type); |
439 | put_unaligned_be16(val: len, p: &entry->len); |
440 | put_unaligned_be32(fc_host_bootbios_state(lport->host), |
441 | p: &entry->value); |
442 | |
443 | /* Vendor identifier */ |
444 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
445 | FC_FDMI_HBA_ATTR_BIOSSTATE_LEN); |
446 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
447 | len += FC_FDMI_HBA_ATTR_VENDORIDENTIFIER_LEN; |
448 | put_unaligned_be16(val: FC_FDMI_HBA_ATTR_VENDORIDENTIFIER, |
449 | p: &entry->type); |
450 | put_unaligned_be16(val: len, p: &entry->len); |
451 | fc_ct_ms_fill_attr(entry, |
452 | fc_host_vendor_identifier(lport->host), |
453 | FC_FDMI_HBA_ATTR_VENDORIDENTIFIER_LEN); |
454 | } |
455 | |
456 | break; |
457 | case FC_FDMI_RPA: |
458 | numattrs = 6; |
459 | len = sizeof(struct fc_fdmi_rpa); |
460 | len -= sizeof(struct fc_fdmi_attr_entry); |
461 | len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN); |
462 | len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN; |
463 | len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN; |
464 | len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN; |
465 | len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN; |
466 | len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN; |
467 | len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN; |
468 | |
469 | |
470 | if (fc_host->fdmi_version == FDMI_V2) { |
471 | numattrs += 10; |
472 | |
473 | len += FC_FDMI_PORT_ATTR_NODENAME_LEN; |
474 | len += FC_FDMI_PORT_ATTR_PORTNAME_LEN; |
475 | len += FC_FDMI_PORT_ATTR_SYMBOLICNAME_LEN; |
476 | len += FC_FDMI_PORT_ATTR_PORTTYPE_LEN; |
477 | len += FC_FDMI_PORT_ATTR_SUPPORTEDCLASSSRVC_LEN; |
478 | len += FC_FDMI_PORT_ATTR_FABRICNAME_LEN; |
479 | len += FC_FDMI_PORT_ATTR_CURRENTFC4TYPE_LEN; |
480 | len += FC_FDMI_PORT_ATTR_PORTSTATE_LEN; |
481 | len += FC_FDMI_PORT_ATTR_DISCOVEREDPORTS_LEN; |
482 | len += FC_FDMI_PORT_ATTR_PORTID_LEN; |
483 | |
484 | } |
485 | |
486 | ct = fc_ct_hdr_fill(fp, op, req_size: len, fs_type: FC_FST_MGMT, |
487 | FC_FDMI_SUBTYPE); |
488 | |
489 | /* Port Name */ |
490 | put_unaligned_be64(val: lport->wwpn, |
491 | p: &ct->payload.rpa.port.portname); |
492 | |
493 | /* Port Attributes */ |
494 | put_unaligned_be32(val: numattrs, |
495 | p: &ct->payload.rpa.hba_attrs.numattrs); |
496 | |
497 | hba_attrs = &ct->payload.rpa.hba_attrs; |
498 | entry = (struct fc_fdmi_attr_entry *)hba_attrs->attr; |
499 | |
500 | /* FC4 types */ |
501 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
502 | len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN; |
503 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_FC4TYPES, |
504 | p: &entry->type); |
505 | put_unaligned_be16(val: len, p: &entry->len); |
506 | memcpy(&entry->value, fc_host_supported_fc4s(lport->host), |
507 | FC_FDMI_PORT_ATTR_FC4TYPES_LEN); |
508 | |
509 | /* Supported Speed */ |
510 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
511 | FC_FDMI_PORT_ATTR_FC4TYPES_LEN); |
512 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
513 | len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN; |
514 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_SUPPORTEDSPEED, |
515 | p: &entry->type); |
516 | put_unaligned_be16(val: len, p: &entry->len); |
517 | |
518 | put_unaligned_be32(fc_host_supported_speeds(lport->host), |
519 | p: &entry->value); |
520 | |
521 | /* Current Port Speed */ |
522 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
523 | FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN); |
524 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
525 | len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN; |
526 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_CURRENTPORTSPEED, |
527 | p: &entry->type); |
528 | put_unaligned_be16(val: len, p: &entry->len); |
529 | put_unaligned_be32(val: lport->link_speed, |
530 | p: &entry->value); |
531 | |
532 | /* Max Frame Size */ |
533 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
534 | FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN); |
535 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
536 | len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN; |
537 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_MAXFRAMESIZE, |
538 | p: &entry->type); |
539 | put_unaligned_be16(val: len, p: &entry->len); |
540 | put_unaligned_be32(fc_host_maxframe_size(lport->host), |
541 | p: &entry->value); |
542 | |
543 | /* OS Device Name */ |
544 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
545 | FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN); |
546 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
547 | len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN; |
548 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_OSDEVICENAME, |
549 | p: &entry->type); |
550 | put_unaligned_be16(val: len, p: &entry->len); |
551 | /* Use the sysfs device name */ |
552 | fc_ct_ms_fill_attr(entry, |
553 | in: dev_name(dev: &lport->host->shost_gendev), |
554 | len: strnlen(p: dev_name(dev: &lport->host->shost_gendev), |
555 | FC_FDMI_PORT_ATTR_HOSTNAME_LEN)); |
556 | |
557 | /* Host Name */ |
558 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
559 | FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN); |
560 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
561 | len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN; |
562 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_HOSTNAME, |
563 | p: &entry->type); |
564 | put_unaligned_be16(val: len, p: &entry->len); |
565 | if (strlen(fc_host_system_hostname(lport->host))) |
566 | fc_ct_ms_fill_attr(entry, |
567 | fc_host_system_hostname(lport->host), |
568 | len: strnlen(fc_host_system_hostname(lport->host), |
569 | FC_FDMI_PORT_ATTR_HOSTNAME_LEN)); |
570 | else |
571 | fc_ct_ms_fill_attr(entry, |
572 | in: init_utsname()->nodename, |
573 | FC_FDMI_PORT_ATTR_HOSTNAME_LEN); |
574 | |
575 | |
576 | if (fc_host->fdmi_version == FDMI_V2) { |
577 | |
578 | /* Node name */ |
579 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
580 | FC_FDMI_PORT_ATTR_HOSTNAME_LEN); |
581 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
582 | len += FC_FDMI_PORT_ATTR_NODENAME_LEN; |
583 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_NODENAME, |
584 | p: &entry->type); |
585 | put_unaligned_be16(val: len, p: &entry->len); |
586 | put_unaligned_be64(fc_host_node_name(lport->host), |
587 | p: &entry->value); |
588 | |
589 | /* Port name */ |
590 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
591 | FC_FDMI_PORT_ATTR_NODENAME_LEN); |
592 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
593 | len += FC_FDMI_PORT_ATTR_PORTNAME_LEN; |
594 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_PORTNAME, |
595 | p: &entry->type); |
596 | put_unaligned_be16(val: len, p: &entry->len); |
597 | put_unaligned_be64(val: lport->wwpn, |
598 | p: &entry->value); |
599 | |
600 | /* Port symbolic name */ |
601 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
602 | FC_FDMI_PORT_ATTR_PORTNAME_LEN); |
603 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
604 | len += FC_FDMI_PORT_ATTR_SYMBOLICNAME_LEN; |
605 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_SYMBOLICNAME, |
606 | p: &entry->type); |
607 | put_unaligned_be16(val: len, p: &entry->len); |
608 | fc_ct_ms_fill_attr(entry, |
609 | fc_host_symbolic_name(lport->host), |
610 | FC_FDMI_PORT_ATTR_SYMBOLICNAME_LEN); |
611 | |
612 | /* Port type */ |
613 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
614 | FC_FDMI_PORT_ATTR_SYMBOLICNAME_LEN); |
615 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
616 | len += FC_FDMI_PORT_ATTR_PORTTYPE_LEN; |
617 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_PORTTYPE, |
618 | p: &entry->type); |
619 | put_unaligned_be16(val: len, p: &entry->len); |
620 | put_unaligned_be32(fc_host_port_type(lport->host), |
621 | p: &entry->value); |
622 | |
623 | /* Supported class of service */ |
624 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
625 | FC_FDMI_PORT_ATTR_PORTTYPE_LEN); |
626 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
627 | len += FC_FDMI_PORT_ATTR_SUPPORTEDCLASSSRVC_LEN; |
628 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_SUPPORTEDCLASSSRVC, |
629 | p: &entry->type); |
630 | put_unaligned_be16(val: len, p: &entry->len); |
631 | put_unaligned_be32(fc_host_supported_classes(lport->host), |
632 | p: &entry->value); |
633 | |
634 | /* Port Fabric name */ |
635 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
636 | FC_FDMI_PORT_ATTR_SUPPORTEDCLASSSRVC_LEN); |
637 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
638 | len += FC_FDMI_PORT_ATTR_FABRICNAME_LEN; |
639 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_FABRICNAME, |
640 | p: &entry->type); |
641 | put_unaligned_be16(val: len, p: &entry->len); |
642 | put_unaligned_be64(fc_host_fabric_name(lport->host), |
643 | p: &entry->value); |
644 | |
645 | /* Port active FC-4 */ |
646 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
647 | FC_FDMI_PORT_ATTR_FABRICNAME_LEN); |
648 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
649 | len += FC_FDMI_PORT_ATTR_CURRENTFC4TYPE_LEN; |
650 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_CURRENTFC4TYPE, |
651 | p: &entry->type); |
652 | put_unaligned_be16(val: len, p: &entry->len); |
653 | memcpy(&entry->value, fc_host_active_fc4s(lport->host), |
654 | FC_FDMI_PORT_ATTR_CURRENTFC4TYPE_LEN); |
655 | |
656 | /* Port state */ |
657 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
658 | FC_FDMI_PORT_ATTR_CURRENTFC4TYPE_LEN); |
659 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
660 | len += FC_FDMI_PORT_ATTR_PORTSTATE_LEN; |
661 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_PORTSTATE, |
662 | p: &entry->type); |
663 | put_unaligned_be16(val: len, p: &entry->len); |
664 | put_unaligned_be32(fc_host_port_state(lport->host), |
665 | p: &entry->value); |
666 | |
667 | /* Discovered ports */ |
668 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
669 | FC_FDMI_PORT_ATTR_PORTSTATE_LEN); |
670 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
671 | len += FC_FDMI_PORT_ATTR_DISCOVEREDPORTS_LEN; |
672 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_DISCOVEREDPORTS, |
673 | p: &entry->type); |
674 | put_unaligned_be16(val: len, p: &entry->len); |
675 | put_unaligned_be32(fc_host_num_discovered_ports(lport->host), |
676 | p: &entry->value); |
677 | |
678 | /* Port ID */ |
679 | entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + |
680 | FC_FDMI_PORT_ATTR_DISCOVEREDPORTS_LEN); |
681 | len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; |
682 | len += FC_FDMI_PORT_ATTR_PORTID_LEN; |
683 | put_unaligned_be16(val: FC_FDMI_PORT_ATTR_PORTID, |
684 | p: &entry->type); |
685 | put_unaligned_be16(val: len, p: &entry->len); |
686 | put_unaligned_be32(fc_host_port_id(lport->host), |
687 | p: &entry->value); |
688 | } |
689 | |
690 | break; |
691 | case FC_FDMI_DPRT: |
692 | len = sizeof(struct fc_fdmi_dprt); |
693 | ct = fc_ct_hdr_fill(fp, op, req_size: len, fs_type: FC_FST_MGMT, |
694 | FC_FDMI_SUBTYPE); |
695 | /* Port Name */ |
696 | put_unaligned_be64(val: lport->wwpn, |
697 | p: &ct->payload.dprt.port.portname); |
698 | break; |
699 | case FC_FDMI_DHBA: |
700 | len = sizeof(struct fc_fdmi_dhba); |
701 | ct = fc_ct_hdr_fill(fp, op, req_size: len, fs_type: FC_FST_MGMT, |
702 | FC_FDMI_SUBTYPE); |
703 | /* HBA Identifier */ |
704 | put_unaligned_be64(val: lport->wwpn, p: &ct->payload.dhba.hbaid.id); |
705 | break; |
706 | default: |
707 | return -EINVAL; |
708 | } |
709 | *r_ctl = FC_RCTL_DD_UNSOL_CTL; |
710 | *fh_type = FC_TYPE_CT; |
711 | return 0; |
712 | } |
713 | |
714 | /** |
715 | * fc_ct_fill() - Fill in a common transport service request frame |
716 | * @lport: local port. |
717 | * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries. |
718 | * @fp: frame to contain payload. |
719 | * @op: CT opcode. |
720 | * @r_ctl: pointer to FC header R_CTL. |
721 | * @fh_type: pointer to FC-4 type. |
722 | */ |
723 | static inline int fc_ct_fill(struct fc_lport *lport, |
724 | u32 fc_id, struct fc_frame *fp, |
725 | unsigned int op, enum fc_rctl *r_ctl, |
726 | enum fc_fh_type *fh_type, u32 *did) |
727 | { |
728 | int rc = -EINVAL; |
729 | |
730 | switch (fc_id) { |
731 | case FC_FID_MGMT_SERV: |
732 | rc = fc_ct_ms_fill(lport, fc_id, fp, op, r_ctl, fh_type); |
733 | *did = FC_FID_MGMT_SERV; |
734 | break; |
735 | case FC_FID_DIR_SERV: |
736 | default: |
737 | rc = fc_ct_ns_fill(lport, fc_id, fp, op, r_ctl, fh_type); |
738 | *did = FC_FID_DIR_SERV; |
739 | break; |
740 | } |
741 | |
742 | return rc; |
743 | } |
744 | /** |
745 | * fc_plogi_fill - Fill in plogi request frame |
746 | */ |
747 | static inline void fc_plogi_fill(struct fc_lport *lport, struct fc_frame *fp, |
748 | unsigned int op) |
749 | { |
750 | struct fc_els_flogi *plogi; |
751 | struct fc_els_csp *csp; |
752 | struct fc_els_cssp *cp; |
753 | |
754 | plogi = fc_frame_payload_get(fp, len: sizeof(*plogi)); |
755 | memset(plogi, 0, sizeof(*plogi)); |
756 | plogi->fl_cmd = (u8) op; |
757 | put_unaligned_be64(val: lport->wwpn, p: &plogi->fl_wwpn); |
758 | put_unaligned_be64(val: lport->wwnn, p: &plogi->fl_wwnn); |
759 | |
760 | csp = &plogi->fl_csp; |
761 | csp->sp_hi_ver = 0x20; |
762 | csp->sp_lo_ver = 0x20; |
763 | csp->sp_bb_cred = htons(10); /* this gets set by gateway */ |
764 | csp->sp_bb_data = htons((u16) lport->mfs); |
765 | cp = &plogi->fl_cssp[3 - 1]; /* class 3 parameters */ |
766 | cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); |
767 | csp->sp_features = htons(FC_SP_FT_CIRO); |
768 | csp->sp_tot_seq = htons(255); /* seq. we accept */ |
769 | csp->sp_rel_off = htons(0x1f); |
770 | csp->sp_e_d_tov = htonl(lport->e_d_tov); |
771 | |
772 | cp->cp_rdfs = htons((u16) lport->mfs); |
773 | cp->cp_con_seq = htons(255); |
774 | cp->cp_open_seq = 1; |
775 | } |
776 | |
777 | /** |
778 | * fc_flogi_fill - Fill in a flogi request frame. |
779 | */ |
780 | static inline void fc_flogi_fill(struct fc_lport *lport, struct fc_frame *fp) |
781 | { |
782 | struct fc_els_csp *sp; |
783 | struct fc_els_cssp *cp; |
784 | struct fc_els_flogi *flogi; |
785 | |
786 | flogi = fc_frame_payload_get(fp, len: sizeof(*flogi)); |
787 | memset(flogi, 0, sizeof(*flogi)); |
788 | flogi->fl_cmd = (u8) ELS_FLOGI; |
789 | put_unaligned_be64(val: lport->wwpn, p: &flogi->fl_wwpn); |
790 | put_unaligned_be64(val: lport->wwnn, p: &flogi->fl_wwnn); |
791 | sp = &flogi->fl_csp; |
792 | sp->sp_hi_ver = 0x20; |
793 | sp->sp_lo_ver = 0x20; |
794 | sp->sp_bb_cred = htons(10); /* this gets set by gateway */ |
795 | sp->sp_bb_data = htons((u16) lport->mfs); |
796 | cp = &flogi->fl_cssp[3 - 1]; /* class 3 parameters */ |
797 | cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); |
798 | if (lport->does_npiv) |
799 | sp->sp_features = htons(FC_SP_FT_NPIV); |
800 | } |
801 | |
802 | /** |
803 | * fc_fdisc_fill - Fill in a fdisc request frame. |
804 | */ |
805 | static inline void fc_fdisc_fill(struct fc_lport *lport, struct fc_frame *fp) |
806 | { |
807 | struct fc_els_csp *sp; |
808 | struct fc_els_cssp *cp; |
809 | struct fc_els_flogi *fdisc; |
810 | |
811 | fdisc = fc_frame_payload_get(fp, len: sizeof(*fdisc)); |
812 | memset(fdisc, 0, sizeof(*fdisc)); |
813 | fdisc->fl_cmd = (u8) ELS_FDISC; |
814 | put_unaligned_be64(val: lport->wwpn, p: &fdisc->fl_wwpn); |
815 | put_unaligned_be64(val: lport->wwnn, p: &fdisc->fl_wwnn); |
816 | sp = &fdisc->fl_csp; |
817 | sp->sp_hi_ver = 0x20; |
818 | sp->sp_lo_ver = 0x20; |
819 | sp->sp_bb_cred = htons(10); /* this gets set by gateway */ |
820 | sp->sp_bb_data = htons((u16) lport->mfs); |
821 | cp = &fdisc->fl_cssp[3 - 1]; /* class 3 parameters */ |
822 | cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); |
823 | } |
824 | |
825 | /** |
826 | * fc_logo_fill - Fill in a logo request frame. |
827 | */ |
828 | static inline void fc_logo_fill(struct fc_lport *lport, struct fc_frame *fp) |
829 | { |
830 | struct fc_els_logo *logo; |
831 | |
832 | logo = fc_frame_payload_get(fp, len: sizeof(*logo)); |
833 | memset(logo, 0, sizeof(*logo)); |
834 | logo->fl_cmd = ELS_LOGO; |
835 | hton24(p: logo->fl_n_port_id, v: lport->port_id); |
836 | logo->fl_n_port_wwn = htonll(lport->wwpn); |
837 | } |
838 | |
839 | /** |
840 | * fc_rtv_fill - Fill in RTV (read timeout value) request frame. |
841 | */ |
842 | static inline void fc_rtv_fill(struct fc_lport *lport, struct fc_frame *fp) |
843 | { |
844 | struct fc_els_rtv *rtv; |
845 | |
846 | rtv = fc_frame_payload_get(fp, len: sizeof(*rtv)); |
847 | memset(rtv, 0, sizeof(*rtv)); |
848 | rtv->rtv_cmd = ELS_RTV; |
849 | } |
850 | |
851 | /** |
852 | * fc_rec_fill - Fill in rec request frame |
853 | */ |
854 | static inline void fc_rec_fill(struct fc_lport *lport, struct fc_frame *fp) |
855 | { |
856 | struct fc_els_rec *rec; |
857 | struct fc_exch *ep = fc_seq_exch(fr_seq(fp)); |
858 | |
859 | rec = fc_frame_payload_get(fp, len: sizeof(*rec)); |
860 | memset(rec, 0, sizeof(*rec)); |
861 | rec->rec_cmd = ELS_REC; |
862 | hton24(p: rec->rec_s_id, v: lport->port_id); |
863 | rec->rec_ox_id = htons(ep->oxid); |
864 | rec->rec_rx_id = htons(ep->rxid); |
865 | } |
866 | |
867 | /** |
868 | * fc_prli_fill - Fill in prli request frame |
869 | */ |
870 | static inline void fc_prli_fill(struct fc_lport *lport, struct fc_frame *fp) |
871 | { |
872 | struct { |
873 | struct fc_els_prli prli; |
874 | struct fc_els_spp spp; |
875 | } *pp; |
876 | |
877 | pp = fc_frame_payload_get(fp, len: sizeof(*pp)); |
878 | memset(pp, 0, sizeof(*pp)); |
879 | pp->prli.prli_cmd = ELS_PRLI; |
880 | pp->prli.prli_spp_len = sizeof(struct fc_els_spp); |
881 | pp->prli.prli_len = htons(sizeof(*pp)); |
882 | pp->spp.spp_type = FC_TYPE_FCP; |
883 | pp->spp.spp_flags = FC_SPP_EST_IMG_PAIR; |
884 | pp->spp.spp_params = htonl(lport->service_params); |
885 | } |
886 | |
887 | /** |
888 | * fc_scr_fill - Fill in a scr request frame. |
889 | */ |
890 | static inline void fc_scr_fill(struct fc_lport *lport, struct fc_frame *fp) |
891 | { |
892 | struct fc_els_scr *scr; |
893 | |
894 | scr = fc_frame_payload_get(fp, len: sizeof(*scr)); |
895 | memset(scr, 0, sizeof(*scr)); |
896 | scr->scr_cmd = ELS_SCR; |
897 | scr->scr_reg_func = ELS_SCRF_FULL; |
898 | } |
899 | |
900 | /** |
901 | * fc_els_fill - Fill in an ELS request frame |
902 | */ |
903 | static inline int fc_els_fill(struct fc_lport *lport, |
904 | u32 did, |
905 | struct fc_frame *fp, unsigned int op, |
906 | enum fc_rctl *r_ctl, enum fc_fh_type *fh_type) |
907 | { |
908 | switch (op) { |
909 | case ELS_ADISC: |
910 | fc_adisc_fill(lport, fp); |
911 | break; |
912 | |
913 | case ELS_PLOGI: |
914 | fc_plogi_fill(lport, fp, op: ELS_PLOGI); |
915 | break; |
916 | |
917 | case ELS_FLOGI: |
918 | fc_flogi_fill(lport, fp); |
919 | break; |
920 | |
921 | case ELS_FDISC: |
922 | fc_fdisc_fill(lport, fp); |
923 | break; |
924 | |
925 | case ELS_LOGO: |
926 | fc_logo_fill(lport, fp); |
927 | break; |
928 | |
929 | case ELS_RTV: |
930 | fc_rtv_fill(lport, fp); |
931 | break; |
932 | |
933 | case ELS_REC: |
934 | fc_rec_fill(lport, fp); |
935 | break; |
936 | |
937 | case ELS_PRLI: |
938 | fc_prli_fill(lport, fp); |
939 | break; |
940 | |
941 | case ELS_SCR: |
942 | fc_scr_fill(lport, fp); |
943 | break; |
944 | |
945 | default: |
946 | return -EINVAL; |
947 | } |
948 | |
949 | *r_ctl = FC_RCTL_ELS_REQ; |
950 | *fh_type = FC_TYPE_ELS; |
951 | return 0; |
952 | } |
953 | #endif /* _FC_ENCODE_H_ */ |
954 | |