Blame view

include/scsi/fc_encode.h 21.6 KB
42e9a92fe   Robert Love   [SCSI] libfc: A m...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  /*
   * Copyright(c) 2008 Intel Corporation. All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms and conditions of the GNU General Public License,
   * version 2, as published by the Free Software Foundation.
   *
   * This program is distributed in the hope it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   * more details.
   *
   * You should have received a copy of the GNU General Public License along with
   * this program; if not, write to the Free Software Foundation, Inc.,
   * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Maintained at www.Open-FCoE.org
   */
  
  #ifndef _FC_ENCODE_H_
  #define _FC_ENCODE_H_
  #include <asm/unaligned.h>
d78c317f6   Neerav Parikh   [SCSI] libfc: Add...
23
  #include <linux/utsname.h>
42e9a92fe   Robert Love   [SCSI] libfc: A m...
24

24f089e2f   Joe Eykholt   [SCSI] libfc: add...
25
26
27
28
29
30
  /*
   * F_CTL values for simple requests and responses.
   */
  #define FC_FCTL_REQ	(FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT)
  #define FC_FCTL_RESP	(FC_FC_EX_CTX | FC_FC_LAST_SEQ | \
  			FC_FC_END_SEQ | FC_FC_SEQ_INIT)
42e9a92fe   Robert Love   [SCSI] libfc: A m...
31
32
33
34
35
36
37
38
39
40
41
  struct fc_ns_rft {
  	struct fc_ns_fid fid;	/* port ID object */
  	struct fc_ns_fts fts;	/* FC4-types object */
  };
  
  struct fc_ct_req {
  	struct fc_ct_hdr hdr;
  	union {
  		struct fc_ns_gid_ft gid;
  		struct fc_ns_rn_id  rn;
  		struct fc_ns_rft rft;
ab593b187   Joe Eykholt   [SCSI] libfc: reg...
42
  		struct fc_ns_rff_id rff;
2ab7e1ecb   Joe Eykholt   [SCSI] libfc: sen...
43
  		struct fc_ns_fid fid;
5baa17c3e   Chris Leech   [SCSI] libfc: Reg...
44
  		struct fc_ns_rsnn snn;
c9866a548   Chris Leech   [SCSI] libfc: Reg...
45
  		struct fc_ns_rspn spn;
d78c317f6   Neerav Parikh   [SCSI] libfc: Add...
46
47
48
49
  		struct fc_fdmi_rhba rhba;
  		struct fc_fdmi_rpa  rpa;
  		struct fc_fdmi_dprt dprt;
  		struct fc_fdmi_dhba dhba;
42e9a92fe   Robert Love   [SCSI] libfc: A m...
50
51
  	} payload;
  };
059f04d4a   Bhanu Prakash Gollapudi   [SCSI] libfc: int...
52
53
54
55
  static inline void __fc_fill_fc_hdr(struct fc_frame_header *fh,
  				    enum fc_rctl r_ctl,
  				    u32 did, u32 sid, enum fc_fh_type type,
  				    u32 f_ctl, u32 parm_offset)
42e9a92fe   Robert Love   [SCSI] libfc: A m...
56
  {
42e9a92fe   Robert Love   [SCSI] libfc: A m...
57
58
59
60
61
62
63
64
65
66
67
68
  	WARN_ON(r_ctl == 0);
  	fh->fh_r_ctl = r_ctl;
  	hton24(fh->fh_d_id, did);
  	hton24(fh->fh_s_id, sid);
  	fh->fh_type = type;
  	hton24(fh->fh_f_ctl, f_ctl);
  	fh->fh_cs_ctl = 0;
  	fh->fh_df_ctl = 0;
  	fh->fh_parm_offset = htonl(parm_offset);
  }
  
  /**
059f04d4a   Bhanu Prakash Gollapudi   [SCSI] libfc: int...
69
70
71
72
73
74
75
76
77
78
79
80
81
   * fill FC header fields in specified fc_frame
   */
  static inline void fc_fill_fc_hdr(struct fc_frame *fp, enum fc_rctl r_ctl,
  				  u32 did, u32 sid, enum fc_fh_type type,
  				  u32 f_ctl, u32 parm_offset)
  {
  	struct fc_frame_header *fh;
  
  	fh = fc_frame_header_get(fp);
  	__fc_fill_fc_hdr(fh, r_ctl, did, sid, type, f_ctl, parm_offset);
  }
  
  /**
370c3bd05   Joe Eykholt   [SCSI] libfc: use...
82
83
84
85
86
87
88
89
90
91
92
93
94
   * fc_adisc_fill() - Fill in adisc request frame
   * @lport: local port.
   * @fp: fc frame where payload will be placed.
   */
  static inline void fc_adisc_fill(struct fc_lport *lport, struct fc_frame *fp)
  {
  	struct fc_els_adisc *adisc;
  
  	adisc = fc_frame_payload_get(fp, sizeof(*adisc));
  	memset(adisc, 0, sizeof(*adisc));
  	adisc->adisc_cmd = ELS_ADISC;
  	put_unaligned_be64(lport->wwpn, &adisc->adisc_wwpn);
  	put_unaligned_be64(lport->wwnn, &adisc->adisc_wwnn);
7b2787ec1   Robert Love   [SCSI] libfc: Mov...
95
  	hton24(adisc->adisc_port_id, lport->port_id);
370c3bd05   Joe Eykholt   [SCSI] libfc: use...
96
97
98
  }
  
  /**
42e9a92fe   Robert Love   [SCSI] libfc: A m...
99
100
101
102
   * fc_ct_hdr_fill- fills ct header and reset ct payload
   * returns pointer to ct request.
   */
  static inline struct fc_ct_req *fc_ct_hdr_fill(const struct fc_frame *fp,
1ea2c1daf   Neerav Parikh   [SCSI] libfc: Mak...
103
104
105
  					       unsigned int op, size_t req_size,
  					       enum fc_ct_fs_type fs_type,
  					       u8 subtype)
42e9a92fe   Robert Love   [SCSI] libfc: A m...
106
107
108
109
110
111
112
113
  {
  	struct fc_ct_req *ct;
  	size_t ct_plen;
  
  	ct_plen  = sizeof(struct fc_ct_hdr) + req_size;
  	ct = fc_frame_payload_get(fp, ct_plen);
  	memset(ct, 0, ct_plen);
  	ct->hdr.ct_rev = FC_CT_REV;
1ea2c1daf   Neerav Parikh   [SCSI] libfc: Mak...
114
115
  	ct->hdr.ct_fs_type = fs_type;
  	ct->hdr.ct_fs_subtype = subtype;
42e9a92fe   Robert Love   [SCSI] libfc: A m...
116
117
118
119
120
  	ct->hdr.ct_cmd = htons((u16) op);
  	return ct;
  }
  
  /**
1ea2c1daf   Neerav Parikh   [SCSI] libfc: Mak...
121
   * fc_ct_ns_fill() - Fill in a name service request frame
2ab7e1ecb   Joe Eykholt   [SCSI] libfc: sen...
122
123
124
125
126
127
   * @lport: local port.
   * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries.
   * @fp: frame to contain payload.
   * @op: CT opcode.
   * @r_ctl: pointer to FC header R_CTL.
   * @fh_type: pointer to FC-4 type.
42e9a92fe   Robert Love   [SCSI] libfc: A m...
128
   */
1ea2c1daf   Neerav Parikh   [SCSI] libfc: Mak...
129
  static inline int fc_ct_ns_fill(struct fc_lport *lport,
2ab7e1ecb   Joe Eykholt   [SCSI] libfc: sen...
130
  		      u32 fc_id, struct fc_frame *fp,
a46f327aa   Joe Eykholt   [SCSI] libfc: cha...
131
  		      unsigned int op, enum fc_rctl *r_ctl,
42e9a92fe   Robert Love   [SCSI] libfc: A m...
132
133
134
  		      enum fc_fh_type *fh_type)
  {
  	struct fc_ct_req *ct;
5f9a056db   Joe Eykholt   [SCSI] libfc: fix...
135
  	size_t len;
42e9a92fe   Robert Love   [SCSI] libfc: A m...
136
137
138
  
  	switch (op) {
  	case FC_NS_GPN_FT:
1ea2c1daf   Neerav Parikh   [SCSI] libfc: Mak...
139
140
  		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_gid_ft),
  				    FC_FST_DIR, FC_NS_SUBTYPE);
42e9a92fe   Robert Love   [SCSI] libfc: A m...
141
142
  		ct->payload.gid.fn_fc4_type = FC_TYPE_FCP;
  		break;
2ab7e1ecb   Joe Eykholt   [SCSI] libfc: sen...
143
  	case FC_NS_GPN_ID:
1ea2c1daf   Neerav Parikh   [SCSI] libfc: Mak...
144
145
146
  		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_fid),
  				    FC_FST_DIR, FC_NS_SUBTYPE);
  		ct->payload.gid.fn_fc4_type = FC_TYPE_FCP;
2ab7e1ecb   Joe Eykholt   [SCSI] libfc: sen...
147
148
  		hton24(ct->payload.fid.fp_fid, fc_id);
  		break;
42e9a92fe   Robert Love   [SCSI] libfc: A m...
149
  	case FC_NS_RFT_ID:
1ea2c1daf   Neerav Parikh   [SCSI] libfc: Mak...
150
151
  		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rft),
  				    FC_FST_DIR, FC_NS_SUBTYPE);
7b2787ec1   Robert Love   [SCSI] libfc: Mov...
152
  		hton24(ct->payload.rft.fid.fp_fid, lport->port_id);
42e9a92fe   Robert Love   [SCSI] libfc: A m...
153
154
  		ct->payload.rft.fts = lport->fcts;
  		break;
ab593b187   Joe Eykholt   [SCSI] libfc: reg...
155
  	case FC_NS_RFF_ID:
1ea2c1daf   Neerav Parikh   [SCSI] libfc: Mak...
156
157
  		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rff_id),
  				    FC_FST_DIR, FC_NS_SUBTYPE);
7b2787ec1   Robert Love   [SCSI] libfc: Mov...
158
  		hton24(ct->payload.rff.fr_fid.fp_fid, lport->port_id);
ab593b187   Joe Eykholt   [SCSI] libfc: reg...
159
160
161
162
163
164
  		ct->payload.rff.fr_type = FC_TYPE_FCP;
  		if (lport->service_params & FCP_SPPF_INIT_FCN)
  			ct->payload.rff.fr_feat = FCP_FEAT_INIT;
  		if (lport->service_params & FCP_SPPF_TARG_FCN)
  			ct->payload.rff.fr_feat |= FCP_FEAT_TARG;
  		break;
c9c7bd7a5   Chris Leech   [SCSI] libfc: RNN...
165
  	case FC_NS_RNN_ID:
1ea2c1daf   Neerav Parikh   [SCSI] libfc: Mak...
166
167
  		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rn_id),
  				    FC_FST_DIR, FC_NS_SUBTYPE);
7b2787ec1   Robert Love   [SCSI] libfc: Mov...
168
  		hton24(ct->payload.rn.fr_fid.fp_fid, lport->port_id);
c9c7bd7a5   Chris Leech   [SCSI] libfc: RNN...
169
  		put_unaligned_be64(lport->wwnn, &ct->payload.rn.fr_wwn);
42e9a92fe   Robert Love   [SCSI] libfc: A m...
170
  		break;
c9866a548   Chris Leech   [SCSI] libfc: Reg...
171
  	case FC_NS_RSPN_ID:
5f9a056db   Joe Eykholt   [SCSI] libfc: fix...
172
  		len = strnlen(fc_host_symbolic_name(lport->host), 255);
1ea2c1daf   Neerav Parikh   [SCSI] libfc: Mak...
173
174
  		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rspn) + len,
  				    FC_FST_DIR, FC_NS_SUBTYPE);
7b2787ec1   Robert Love   [SCSI] libfc: Mov...
175
  		hton24(ct->payload.spn.fr_fid.fp_fid, lport->port_id);
c9866a548   Chris Leech   [SCSI] libfc: Reg...
176
  		strncpy(ct->payload.spn.fr_name,
5f9a056db   Joe Eykholt   [SCSI] libfc: fix...
177
178
  			fc_host_symbolic_name(lport->host), len);
  		ct->payload.spn.fr_name_len = len;
c9866a548   Chris Leech   [SCSI] libfc: Reg...
179
  		break;
5baa17c3e   Chris Leech   [SCSI] libfc: Reg...
180
  	case FC_NS_RSNN_NN:
5f9a056db   Joe Eykholt   [SCSI] libfc: fix...
181
  		len = strnlen(fc_host_symbolic_name(lport->host), 255);
1ea2c1daf   Neerav Parikh   [SCSI] libfc: Mak...
182
183
  		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rsnn) + len,
  				    FC_FST_DIR, FC_NS_SUBTYPE);
5baa17c3e   Chris Leech   [SCSI] libfc: Reg...
184
185
  		put_unaligned_be64(lport->wwnn, &ct->payload.snn.fr_wwn);
  		strncpy(ct->payload.snn.fr_name,
5f9a056db   Joe Eykholt   [SCSI] libfc: fix...
186
187
  			fc_host_symbolic_name(lport->host), len);
  		ct->payload.snn.fr_name_len = len;
5baa17c3e   Chris Leech   [SCSI] libfc: Reg...
188
  		break;
42e9a92fe   Robert Love   [SCSI] libfc: A m...
189
  	default:
42e9a92fe   Robert Love   [SCSI] libfc: A m...
190
191
192
  		return -EINVAL;
  	}
  	*r_ctl = FC_RCTL_DD_UNSOL_CTL;
42e9a92fe   Robert Love   [SCSI] libfc: A m...
193
194
195
196
197
  	*fh_type = FC_TYPE_CT;
  	return 0;
  }
  
  /**
d78c317f6   Neerav Parikh   [SCSI] libfc: Add...
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
   * fc_ct_ms_fill() - Fill in a mgmt service request frame
   * @lport: local port.
   * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries.
   * @fp: frame to contain payload.
   * @op: CT opcode.
   * @r_ctl: pointer to FC header R_CTL.
   * @fh_type: pointer to FC-4 type.
   */
  static inline int fc_ct_ms_fill(struct fc_lport *lport,
  		      u32 fc_id, struct fc_frame *fp,
  		      unsigned int op, enum fc_rctl *r_ctl,
  		      enum fc_fh_type *fh_type)
  {
  	struct fc_ct_req *ct;
  	size_t len;
  	struct fc_fdmi_attr_entry *entry;
  	struct fs_fdmi_attrs *hba_attrs;
  	int numattrs = 0;
  
  	switch (op) {
  	case FC_FDMI_RHBA:
  		numattrs = 10;
  		len = sizeof(struct fc_fdmi_rhba);
  		len -= sizeof(struct fc_fdmi_attr_entry);
  		len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
  		len += FC_FDMI_HBA_ATTR_NODENAME_LEN;
  		len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN;
  		len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN;
  		len += FC_FDMI_HBA_ATTR_MODEL_LEN;
  		len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN;
  		len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN;
  		len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN;
  		len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN;
  		len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN;
  		len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN;
  		ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
  				    FC_FDMI_SUBTYPE);
  
  		/* HBA Identifier */
  		put_unaligned_be64(lport->wwpn, &ct->payload.rhba.hbaid.id);
  		/* Number of Ports - always 1 */
  		put_unaligned_be32(1, &ct->payload.rhba.port.numport);
  		/* Port Name */
  		put_unaligned_be64(lport->wwpn,
  				   &ct->payload.rhba.port.port[0].portname);
  
  		/* HBA Attributes */
  		put_unaligned_be32(numattrs,
  				   &ct->payload.rhba.hba_attrs.numattrs);
  		hba_attrs = &ct->payload.rhba.hba_attrs;
  		entry = (struct fc_fdmi_attr_entry *)hba_attrs->attr;
  		/* NodeName*/
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_HBA_ATTR_NODENAME_LEN;
  		put_unaligned_be16(FC_FDMI_HBA_ATTR_NODENAME,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		put_unaligned_be64(lport->wwnn,
  				   (__be64 *)&entry->value[0]);
  
  		/* Manufacturer */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_HBA_ATTR_NODENAME_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN;
  		put_unaligned_be16(FC_FDMI_HBA_ATTR_MANUFACTURER,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		strncpy((char *)&entry->value,
  			fc_host_manufacturer(lport->host),
  			FC_FDMI_HBA_ATTR_MANUFACTURER_LEN);
  
  		/* SerialNumber */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_HBA_ATTR_MANUFACTURER_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN;
  		put_unaligned_be16(FC_FDMI_HBA_ATTR_SERIALNUMBER,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		strncpy((char *)&entry->value,
  			fc_host_serial_number(lport->host),
  			FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN);
  
  		/* Model */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_HBA_ATTR_MODEL_LEN;
  		put_unaligned_be16(FC_FDMI_HBA_ATTR_MODEL,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		strncpy((char *)&entry->value,
  			fc_host_model(lport->host),
  			FC_FDMI_HBA_ATTR_MODEL_LEN);
  
  		/* Model Description */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_HBA_ATTR_MODEL_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN;
  		put_unaligned_be16(FC_FDMI_HBA_ATTR_MODELDESCRIPTION,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		strncpy((char *)&entry->value,
  			fc_host_model_description(lport->host),
  			FC_FDMI_HBA_ATTR_MODELDESCR_LEN);
  
  		/* Hardware Version */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_HBA_ATTR_MODELDESCR_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN;
  		put_unaligned_be16(FC_FDMI_HBA_ATTR_HARDWAREVERSION,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		strncpy((char *)&entry->value,
  			fc_host_hardware_version(lport->host),
  			FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN);
  
  		/* Driver Version */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN;
  		put_unaligned_be16(FC_FDMI_HBA_ATTR_DRIVERVERSION,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		strncpy((char *)&entry->value,
  			fc_host_driver_version(lport->host),
  			FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN);
  
  		/* OptionROM Version */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN;
  		put_unaligned_be16(FC_FDMI_HBA_ATTR_OPTIONROMVERSION,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		strncpy((char *)&entry->value,
  			fc_host_optionrom_version(lport->host),
  			FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN);
  
  		/* Firmware Version */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN;
  		put_unaligned_be16(FC_FDMI_HBA_ATTR_FIRMWAREVERSION,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		strncpy((char *)&entry->value,
  			fc_host_firmware_version(lport->host),
  			FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN);
  
  		/* OS Name and Version */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN;
  		put_unaligned_be16(FC_FDMI_HBA_ATTR_OSNAMEVERSION,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		snprintf((char *)&entry->value,
  			FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN,
  			"%s v%s",
  			init_utsname()->sysname,
  			init_utsname()->release);
  		break;
  	case FC_FDMI_RPA:
  		numattrs = 6;
  		len = sizeof(struct fc_fdmi_rpa);
  		len -= sizeof(struct fc_fdmi_attr_entry);
  		len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
  		len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN;
  		len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN;
  		len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN;
  		len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN;
  		len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN;
  		len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN;
  		ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
  				    FC_FDMI_SUBTYPE);
  
  		/* Port Name */
  		put_unaligned_be64(lport->wwpn,
  				   &ct->payload.rpa.port.portname);
  
  		/* Port Attributes */
  		put_unaligned_be32(numattrs,
  				   &ct->payload.rpa.hba_attrs.numattrs);
  
  		hba_attrs = &ct->payload.rpa.hba_attrs;
  		entry = (struct fc_fdmi_attr_entry *)hba_attrs->attr;
  
  		/* FC4 types */
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN;
  		put_unaligned_be16(FC_FDMI_PORT_ATTR_FC4TYPES,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		memcpy(&entry->value, fc_host_supported_fc4s(lport->host),
  		       FC_FDMI_PORT_ATTR_FC4TYPES_LEN);
  
  		/* Supported Speed */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_PORT_ATTR_FC4TYPES_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN;
  		put_unaligned_be16(FC_FDMI_PORT_ATTR_SUPPORTEDSPEED,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  
  		put_unaligned_be32(fc_host_supported_speeds(lport->host),
  				   &entry->value);
  
  		/* Current Port Speed */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN;
  		put_unaligned_be16(FC_FDMI_PORT_ATTR_CURRENTPORTSPEED,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		put_unaligned_be32(lport->link_speed,
  				   &entry->value);
  
  		/* Max Frame Size */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN;
  		put_unaligned_be16(FC_FDMI_PORT_ATTR_MAXFRAMESIZE,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		put_unaligned_be32(fc_host_maxframe_size(lport->host),
  				   &entry->value);
  
  		/* OS Device Name */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN;
  		put_unaligned_be16(FC_FDMI_PORT_ATTR_OSDEVICENAME,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		/* Use the sysfs device name */
  		strncpy((char *)&entry->value,
  			dev_name(&lport->host->shost_gendev),
  			strnlen(dev_name(&lport->host->shost_gendev),
  				FC_FDMI_PORT_ATTR_HOSTNAME_LEN));
  
  		/* Host Name */
  		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
  					FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN);
  		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
  		len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN;
  		put_unaligned_be16(FC_FDMI_PORT_ATTR_HOSTNAME,
  				   &entry->type);
  		put_unaligned_be16(len, &entry->len);
  		if (strlen(fc_host_system_hostname(lport->host)))
  			strncpy((char *)&entry->value,
  				fc_host_system_hostname(lport->host),
  				strnlen(fc_host_system_hostname(lport->host),
  					FC_FDMI_PORT_ATTR_HOSTNAME_LEN));
  		else
  			strncpy((char *)&entry->value,
  				init_utsname()->nodename,
  				FC_FDMI_PORT_ATTR_HOSTNAME_LEN);
  		break;
  	case FC_FDMI_DPRT:
  		len = sizeof(struct fc_fdmi_dprt);
  		ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
  				    FC_FDMI_SUBTYPE);
  		/* Port Name */
  		put_unaligned_be64(lport->wwpn,
  				   &ct->payload.dprt.port.portname);
  		break;
  	case FC_FDMI_DHBA:
  		len = sizeof(struct fc_fdmi_dhba);
  		ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
  				    FC_FDMI_SUBTYPE);
  		/* HBA Identifier */
  		put_unaligned_be64(lport->wwpn, &ct->payload.dhba.hbaid.id);
  		break;
  	default:
  		return -EINVAL;
  	}
  	*r_ctl = FC_RCTL_DD_UNSOL_CTL;
  	*fh_type = FC_TYPE_CT;
  	return 0;
  }
  
  /**
1ea2c1daf   Neerav Parikh   [SCSI] libfc: Mak...
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
   * fc_ct_fill() - Fill in a common transport service request frame
   * @lport: local port.
   * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries.
   * @fp: frame to contain payload.
   * @op: CT opcode.
   * @r_ctl: pointer to FC header R_CTL.
   * @fh_type: pointer to FC-4 type.
   */
  static inline int fc_ct_fill(struct fc_lport *lport,
  		      u32 fc_id, struct fc_frame *fp,
  		      unsigned int op, enum fc_rctl *r_ctl,
  		      enum fc_fh_type *fh_type, u32 *did)
  {
  	int rc = -EINVAL;
  
  	switch (fc_id) {
d78c317f6   Neerav Parikh   [SCSI] libfc: Add...
508
509
510
511
  	case FC_FID_MGMT_SERV:
  		rc = fc_ct_ms_fill(lport, fc_id, fp, op, r_ctl, fh_type);
  		*did = FC_FID_MGMT_SERV;
  		break;
1ea2c1daf   Neerav Parikh   [SCSI] libfc: Mak...
512
513
514
515
516
517
518
519
520
521
  	case FC_FID_DIR_SERV:
  	default:
  		rc = fc_ct_ns_fill(lport, fc_id, fp, op, r_ctl, fh_type);
  		*did = FC_FID_DIR_SERV;
  		break;
  	}
  
  	return rc;
  }
  /**
42e9a92fe   Robert Love   [SCSI] libfc: A m...
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
   * fc_plogi_fill - Fill in plogi request frame
   */
  static inline void fc_plogi_fill(struct fc_lport *lport, struct fc_frame *fp,
  				 unsigned int op)
  {
  	struct fc_els_flogi *plogi;
  	struct fc_els_csp *csp;
  	struct fc_els_cssp *cp;
  
  	plogi = fc_frame_payload_get(fp, sizeof(*plogi));
  	memset(plogi, 0, sizeof(*plogi));
  	plogi->fl_cmd = (u8) op;
  	put_unaligned_be64(lport->wwpn, &plogi->fl_wwpn);
  	put_unaligned_be64(lport->wwnn, &plogi->fl_wwnn);
  
  	csp = &plogi->fl_csp;
  	csp->sp_hi_ver = 0x20;
  	csp->sp_lo_ver = 0x20;
  	csp->sp_bb_cred = htons(10);	/* this gets set by gateway */
  	csp->sp_bb_data = htons((u16) lport->mfs);
  	cp = &plogi->fl_cssp[3 - 1];	/* class 3 parameters */
  	cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ);
  	csp->sp_features = htons(FC_SP_FT_CIRO);
  	csp->sp_tot_seq = htons(255);	/* seq. we accept */
  	csp->sp_rel_off = htons(0x1f);
  	csp->sp_e_d_tov = htonl(lport->e_d_tov);
  
  	cp->cp_rdfs = htons((u16) lport->mfs);
  	cp->cp_con_seq = htons(255);
  	cp->cp_open_seq = 1;
  }
  
  /**
   * fc_flogi_fill - Fill in a flogi request frame.
   */
  static inline void fc_flogi_fill(struct fc_lport *lport, struct fc_frame *fp)
  {
  	struct fc_els_csp *sp;
  	struct fc_els_cssp *cp;
  	struct fc_els_flogi *flogi;
  
  	flogi = fc_frame_payload_get(fp, sizeof(*flogi));
  	memset(flogi, 0, sizeof(*flogi));
  	flogi->fl_cmd = (u8) ELS_FLOGI;
  	put_unaligned_be64(lport->wwpn, &flogi->fl_wwpn);
  	put_unaligned_be64(lport->wwnn, &flogi->fl_wwnn);
  	sp = &flogi->fl_csp;
  	sp->sp_hi_ver = 0x20;
  	sp->sp_lo_ver = 0x20;
  	sp->sp_bb_cred = htons(10);	/* this gets set by gateway */
  	sp->sp_bb_data = htons((u16) lport->mfs);
  	cp = &flogi->fl_cssp[3 - 1];	/* class 3 parameters */
  	cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ);
db36c06cc   Chris Leech   [SCSI] libfc, lib...
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
  	if (lport->does_npiv)
  		sp->sp_features = htons(FC_SP_FT_NPIV);
  }
  
  /**
   * fc_fdisc_fill - Fill in a fdisc request frame.
   */
  static inline void fc_fdisc_fill(struct fc_lport *lport, struct fc_frame *fp)
  {
  	struct fc_els_csp *sp;
  	struct fc_els_cssp *cp;
  	struct fc_els_flogi *fdisc;
  
  	fdisc = fc_frame_payload_get(fp, sizeof(*fdisc));
  	memset(fdisc, 0, sizeof(*fdisc));
  	fdisc->fl_cmd = (u8) ELS_FDISC;
  	put_unaligned_be64(lport->wwpn, &fdisc->fl_wwpn);
  	put_unaligned_be64(lport->wwnn, &fdisc->fl_wwnn);
  	sp = &fdisc->fl_csp;
  	sp->sp_hi_ver = 0x20;
  	sp->sp_lo_ver = 0x20;
  	sp->sp_bb_cred = htons(10);	/* this gets set by gateway */
  	sp->sp_bb_data = htons((u16) lport->mfs);
  	cp = &fdisc->fl_cssp[3 - 1];	/* class 3 parameters */
  	cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ);
42e9a92fe   Robert Love   [SCSI] libfc: A m...
600
601
602
603
604
605
606
607
608
609
610
611
  }
  
  /**
   * fc_logo_fill - Fill in a logo request frame.
   */
  static inline void fc_logo_fill(struct fc_lport *lport, struct fc_frame *fp)
  {
  	struct fc_els_logo *logo;
  
  	logo = fc_frame_payload_get(fp, sizeof(*logo));
  	memset(logo, 0, sizeof(*logo));
  	logo->fl_cmd = ELS_LOGO;
7b2787ec1   Robert Love   [SCSI] libfc: Mov...
612
  	hton24(logo->fl_n_port_id, lport->port_id);
42e9a92fe   Robert Love   [SCSI] libfc: A m...
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
  	logo->fl_n_port_wwn = htonll(lport->wwpn);
  }
  
  /**
   * fc_rtv_fill - Fill in RTV (read timeout value) request frame.
   */
  static inline void fc_rtv_fill(struct fc_lport *lport, struct fc_frame *fp)
  {
  	struct fc_els_rtv *rtv;
  
  	rtv = fc_frame_payload_get(fp, sizeof(*rtv));
  	memset(rtv, 0, sizeof(*rtv));
  	rtv->rtv_cmd = ELS_RTV;
  }
  
  /**
   * fc_rec_fill - Fill in rec request frame
   */
  static inline void fc_rec_fill(struct fc_lport *lport, struct fc_frame *fp)
  {
  	struct fc_els_rec *rec;
  	struct fc_exch *ep = fc_seq_exch(fr_seq(fp));
  
  	rec = fc_frame_payload_get(fp, sizeof(*rec));
  	memset(rec, 0, sizeof(*rec));
  	rec->rec_cmd = ELS_REC;
7b2787ec1   Robert Love   [SCSI] libfc: Mov...
639
  	hton24(rec->rec_s_id, lport->port_id);
42e9a92fe   Robert Love   [SCSI] libfc: A m...
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
  	rec->rec_ox_id = htons(ep->oxid);
  	rec->rec_rx_id = htons(ep->rxid);
  }
  
  /**
   * fc_prli_fill - Fill in prli request frame
   */
  static inline void fc_prli_fill(struct fc_lport *lport, struct fc_frame *fp)
  {
  	struct {
  		struct fc_els_prli prli;
  		struct fc_els_spp spp;
  	} *pp;
  
  	pp = fc_frame_payload_get(fp, sizeof(*pp));
  	memset(pp, 0, sizeof(*pp));
  	pp->prli.prli_cmd = ELS_PRLI;
  	pp->prli.prli_spp_len = sizeof(struct fc_els_spp);
  	pp->prli.prli_len = htons(sizeof(*pp));
  	pp->spp.spp_type = FC_TYPE_FCP;
  	pp->spp.spp_flags = FC_SPP_EST_IMG_PAIR;
  	pp->spp.spp_params = htonl(lport->service_params);
  }
  
  /**
   * fc_scr_fill - Fill in a scr request frame.
   */
  static inline void fc_scr_fill(struct fc_lport *lport, struct fc_frame *fp)
  {
  	struct fc_els_scr *scr;
  
  	scr = fc_frame_payload_get(fp, sizeof(*scr));
  	memset(scr, 0, sizeof(*scr));
  	scr->scr_cmd = ELS_SCR;
  	scr->scr_reg_func = ELS_SCRF_FULL;
  }
  
  /**
   * fc_els_fill - Fill in an ELS  request frame
   */
9fb9d3283   Joe Eykholt   [SCSI] libfc: mak...
680
  static inline int fc_els_fill(struct fc_lport *lport,
a46f327aa   Joe Eykholt   [SCSI] libfc: cha...
681
  		       u32 did,
42e9a92fe   Robert Love   [SCSI] libfc: A m...
682
  		       struct fc_frame *fp, unsigned int op,
a46f327aa   Joe Eykholt   [SCSI] libfc: cha...
683
  		       enum fc_rctl *r_ctl, enum fc_fh_type *fh_type)
42e9a92fe   Robert Love   [SCSI] libfc: A m...
684
685
  {
  	switch (op) {
370c3bd05   Joe Eykholt   [SCSI] libfc: use...
686
687
688
  	case ELS_ADISC:
  		fc_adisc_fill(lport, fp);
  		break;
42e9a92fe   Robert Love   [SCSI] libfc: A m...
689
690
  	case ELS_PLOGI:
  		fc_plogi_fill(lport, fp, ELS_PLOGI);
42e9a92fe   Robert Love   [SCSI] libfc: A m...
691
692
693
694
  		break;
  
  	case ELS_FLOGI:
  		fc_flogi_fill(lport, fp);
42e9a92fe   Robert Love   [SCSI] libfc: A m...
695
  		break;
db36c06cc   Chris Leech   [SCSI] libfc, lib...
696
697
698
  	case ELS_FDISC:
  		fc_fdisc_fill(lport, fp);
  		break;
42e9a92fe   Robert Love   [SCSI] libfc: A m...
699
700
  	case ELS_LOGO:
  		fc_logo_fill(lport, fp);
42e9a92fe   Robert Love   [SCSI] libfc: A m...
701
702
703
704
  		break;
  
  	case ELS_RTV:
  		fc_rtv_fill(lport, fp);
42e9a92fe   Robert Love   [SCSI] libfc: A m...
705
706
707
708
  		break;
  
  	case ELS_REC:
  		fc_rec_fill(lport, fp);
42e9a92fe   Robert Love   [SCSI] libfc: A m...
709
710
711
712
  		break;
  
  	case ELS_PRLI:
  		fc_prli_fill(lport, fp);
42e9a92fe   Robert Love   [SCSI] libfc: A m...
713
714
715
716
  		break;
  
  	case ELS_SCR:
  		fc_scr_fill(lport, fp);
42e9a92fe   Robert Love   [SCSI] libfc: A m...
717
718
719
  		break;
  
  	default:
42e9a92fe   Robert Love   [SCSI] libfc: A m...
720
721
722
723
724
725
726
727
  		return -EINVAL;
  	}
  
  	*r_ctl = FC_RCTL_ELS_REQ;
  	*fh_type = FC_TYPE_ELS;
  	return 0;
  }
  #endif /* _FC_ENCODE_H_ */