1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. |
4 | * Copyright (c) 2014- QLogic Corporation. |
5 | * All rights reserved |
6 | * www.qlogic.com |
7 | * |
8 | * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. |
9 | */ |
10 | |
11 | /* |
12 | * bfa_attr.c Linux driver configuration interface module. |
13 | */ |
14 | |
15 | #include "bfad_drv.h" |
16 | #include "bfad_im.h" |
17 | |
18 | /* |
19 | * FC transport template entry, get SCSI target port ID. |
20 | */ |
21 | static void |
22 | bfad_im_get_starget_port_id(struct scsi_target *starget) |
23 | { |
24 | struct Scsi_Host *shost; |
25 | struct bfad_im_port_s *im_port; |
26 | struct bfad_s *bfad; |
27 | struct bfad_itnim_s *itnim = NULL; |
28 | u32 fc_id = -1; |
29 | unsigned long flags; |
30 | |
31 | shost = dev_to_shost(dev: starget->dev.parent); |
32 | im_port = (struct bfad_im_port_s *) shost->hostdata[0]; |
33 | bfad = im_port->bfad; |
34 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
35 | |
36 | itnim = bfad_get_itnim(im_port, id: starget->id); |
37 | if (itnim) |
38 | fc_id = bfa_fcs_itnim_get_fcid(itnim: &itnim->fcs_itnim); |
39 | |
40 | fc_starget_port_id(starget) = fc_id; |
41 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
42 | } |
43 | |
44 | /* |
45 | * FC transport template entry, get SCSI target nwwn. |
46 | */ |
47 | static void |
48 | bfad_im_get_starget_node_name(struct scsi_target *starget) |
49 | { |
50 | struct Scsi_Host *shost; |
51 | struct bfad_im_port_s *im_port; |
52 | struct bfad_s *bfad; |
53 | struct bfad_itnim_s *itnim = NULL; |
54 | u64 node_name = 0; |
55 | unsigned long flags; |
56 | |
57 | shost = dev_to_shost(dev: starget->dev.parent); |
58 | im_port = (struct bfad_im_port_s *) shost->hostdata[0]; |
59 | bfad = im_port->bfad; |
60 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
61 | |
62 | itnim = bfad_get_itnim(im_port, id: starget->id); |
63 | if (itnim) |
64 | node_name = bfa_fcs_itnim_get_nwwn(itnim: &itnim->fcs_itnim); |
65 | |
66 | fc_starget_node_name(starget) = cpu_to_be64(node_name); |
67 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
68 | } |
69 | |
70 | /* |
71 | * FC transport template entry, get SCSI target pwwn. |
72 | */ |
73 | static void |
74 | bfad_im_get_starget_port_name(struct scsi_target *starget) |
75 | { |
76 | struct Scsi_Host *shost; |
77 | struct bfad_im_port_s *im_port; |
78 | struct bfad_s *bfad; |
79 | struct bfad_itnim_s *itnim = NULL; |
80 | u64 port_name = 0; |
81 | unsigned long flags; |
82 | |
83 | shost = dev_to_shost(dev: starget->dev.parent); |
84 | im_port = (struct bfad_im_port_s *) shost->hostdata[0]; |
85 | bfad = im_port->bfad; |
86 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
87 | |
88 | itnim = bfad_get_itnim(im_port, id: starget->id); |
89 | if (itnim) |
90 | port_name = bfa_fcs_itnim_get_pwwn(itnim: &itnim->fcs_itnim); |
91 | |
92 | fc_starget_port_name(starget) = cpu_to_be64(port_name); |
93 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
94 | } |
95 | |
96 | /* |
97 | * FC transport template entry, get SCSI host port ID. |
98 | */ |
99 | static void |
100 | bfad_im_get_host_port_id(struct Scsi_Host *shost) |
101 | { |
102 | struct bfad_im_port_s *im_port = |
103 | (struct bfad_im_port_s *) shost->hostdata[0]; |
104 | struct bfad_port_s *port = im_port->port; |
105 | |
106 | fc_host_port_id(shost) = |
107 | bfa_hton3b(bfa_fcs_lport_get_fcid(port->fcs_port)); |
108 | } |
109 | |
110 | /* |
111 | * FC transport template entry, get SCSI host port type. |
112 | */ |
113 | static void |
114 | bfad_im_get_host_port_type(struct Scsi_Host *shost) |
115 | { |
116 | struct bfad_im_port_s *im_port = |
117 | (struct bfad_im_port_s *) shost->hostdata[0]; |
118 | struct bfad_s *bfad = im_port->bfad; |
119 | struct bfa_lport_attr_s port_attr; |
120 | |
121 | bfa_fcs_lport_get_attr(port: &bfad->bfa_fcs.fabric.bport, port_attr: &port_attr); |
122 | |
123 | switch (port_attr.port_type) { |
124 | case BFA_PORT_TYPE_NPORT: |
125 | fc_host_port_type(shost) = FC_PORTTYPE_NPORT; |
126 | break; |
127 | case BFA_PORT_TYPE_NLPORT: |
128 | fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; |
129 | break; |
130 | case BFA_PORT_TYPE_P2P: |
131 | fc_host_port_type(shost) = FC_PORTTYPE_PTP; |
132 | break; |
133 | case BFA_PORT_TYPE_LPORT: |
134 | fc_host_port_type(shost) = FC_PORTTYPE_LPORT; |
135 | break; |
136 | default: |
137 | fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; |
138 | break; |
139 | } |
140 | } |
141 | |
142 | /* |
143 | * FC transport template entry, get SCSI host port state. |
144 | */ |
145 | static void |
146 | bfad_im_get_host_port_state(struct Scsi_Host *shost) |
147 | { |
148 | struct bfad_im_port_s *im_port = |
149 | (struct bfad_im_port_s *) shost->hostdata[0]; |
150 | struct bfad_s *bfad = im_port->bfad; |
151 | struct bfa_port_attr_s attr; |
152 | |
153 | bfa_fcport_get_attr(bfa: &bfad->bfa, attr: &attr); |
154 | |
155 | switch (attr.port_state) { |
156 | case BFA_PORT_ST_LINKDOWN: |
157 | fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; |
158 | break; |
159 | case BFA_PORT_ST_LINKUP: |
160 | fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; |
161 | break; |
162 | case BFA_PORT_ST_DISABLED: |
163 | case BFA_PORT_ST_STOPPED: |
164 | case BFA_PORT_ST_IOCDOWN: |
165 | case BFA_PORT_ST_IOCDIS: |
166 | fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; |
167 | break; |
168 | case BFA_PORT_ST_UNINIT: |
169 | case BFA_PORT_ST_ENABLING_QWAIT: |
170 | case BFA_PORT_ST_ENABLING: |
171 | case BFA_PORT_ST_DISABLING_QWAIT: |
172 | case BFA_PORT_ST_DISABLING: |
173 | default: |
174 | fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; |
175 | break; |
176 | } |
177 | } |
178 | |
179 | /* |
180 | * FC transport template entry, get SCSI host active fc4s. |
181 | */ |
182 | static void |
183 | bfad_im_get_host_active_fc4s(struct Scsi_Host *shost) |
184 | { |
185 | struct bfad_im_port_s *im_port = |
186 | (struct bfad_im_port_s *) shost->hostdata[0]; |
187 | struct bfad_port_s *port = im_port->port; |
188 | |
189 | memset(fc_host_active_fc4s(shost), 0, |
190 | sizeof(fc_host_active_fc4s(shost))); |
191 | |
192 | if (port->supported_fc4s & BFA_LPORT_ROLE_FCP_IM) |
193 | fc_host_active_fc4s(shost)[2] = 1; |
194 | |
195 | fc_host_active_fc4s(shost)[7] = 1; |
196 | } |
197 | |
198 | /* |
199 | * FC transport template entry, get SCSI host link speed. |
200 | */ |
201 | static void |
202 | bfad_im_get_host_speed(struct Scsi_Host *shost) |
203 | { |
204 | struct bfad_im_port_s *im_port = |
205 | (struct bfad_im_port_s *) shost->hostdata[0]; |
206 | struct bfad_s *bfad = im_port->bfad; |
207 | struct bfa_port_attr_s attr; |
208 | |
209 | bfa_fcport_get_attr(bfa: &bfad->bfa, attr: &attr); |
210 | switch (attr.speed) { |
211 | case BFA_PORT_SPEED_10GBPS: |
212 | fc_host_speed(shost) = FC_PORTSPEED_10GBIT; |
213 | break; |
214 | case BFA_PORT_SPEED_16GBPS: |
215 | fc_host_speed(shost) = FC_PORTSPEED_16GBIT; |
216 | break; |
217 | case BFA_PORT_SPEED_8GBPS: |
218 | fc_host_speed(shost) = FC_PORTSPEED_8GBIT; |
219 | break; |
220 | case BFA_PORT_SPEED_4GBPS: |
221 | fc_host_speed(shost) = FC_PORTSPEED_4GBIT; |
222 | break; |
223 | case BFA_PORT_SPEED_2GBPS: |
224 | fc_host_speed(shost) = FC_PORTSPEED_2GBIT; |
225 | break; |
226 | case BFA_PORT_SPEED_1GBPS: |
227 | fc_host_speed(shost) = FC_PORTSPEED_1GBIT; |
228 | break; |
229 | default: |
230 | fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; |
231 | break; |
232 | } |
233 | } |
234 | |
235 | /* |
236 | * FC transport template entry, get SCSI host port type. |
237 | */ |
238 | static void |
239 | bfad_im_get_host_fabric_name(struct Scsi_Host *shost) |
240 | { |
241 | struct bfad_im_port_s *im_port = |
242 | (struct bfad_im_port_s *) shost->hostdata[0]; |
243 | struct bfad_port_s *port = im_port->port; |
244 | wwn_t fabric_nwwn = 0; |
245 | |
246 | fabric_nwwn = bfa_fcs_lport_get_fabric_name(port->fcs_port); |
247 | |
248 | fc_host_fabric_name(shost) = cpu_to_be64(fabric_nwwn); |
249 | |
250 | } |
251 | |
252 | /* |
253 | * FC transport template entry, get BFAD statistics. |
254 | */ |
255 | static struct fc_host_statistics * |
256 | bfad_im_get_stats(struct Scsi_Host *shost) |
257 | { |
258 | struct bfad_im_port_s *im_port = |
259 | (struct bfad_im_port_s *) shost->hostdata[0]; |
260 | struct bfad_s *bfad = im_port->bfad; |
261 | struct bfad_hal_comp fcomp; |
262 | union bfa_port_stats_u *fcstats; |
263 | struct fc_host_statistics *hstats; |
264 | bfa_status_t rc; |
265 | unsigned long flags; |
266 | |
267 | fcstats = kzalloc(size: sizeof(union bfa_port_stats_u), GFP_KERNEL); |
268 | if (fcstats == NULL) |
269 | return NULL; |
270 | |
271 | hstats = &bfad->link_stats; |
272 | init_completion(x: &fcomp.comp); |
273 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
274 | memset(hstats, 0, sizeof(struct fc_host_statistics)); |
275 | rc = bfa_port_get_stats(BFA_FCPORT(&bfad->bfa), |
276 | stats: fcstats, cbfn: bfad_hcb_comp, cbarg: &fcomp); |
277 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
278 | if (rc != BFA_STATUS_OK) { |
279 | kfree(objp: fcstats); |
280 | return NULL; |
281 | } |
282 | |
283 | wait_for_completion(&fcomp.comp); |
284 | |
285 | /* Fill the fc_host_statistics structure */ |
286 | hstats->seconds_since_last_reset = fcstats->fc.secs_reset; |
287 | hstats->tx_frames = fcstats->fc.tx_frames; |
288 | hstats->tx_words = fcstats->fc.tx_words; |
289 | hstats->rx_frames = fcstats->fc.rx_frames; |
290 | hstats->rx_words = fcstats->fc.rx_words; |
291 | hstats->lip_count = fcstats->fc.lip_count; |
292 | hstats->nos_count = fcstats->fc.nos_count; |
293 | hstats->error_frames = fcstats->fc.error_frames; |
294 | hstats->dumped_frames = fcstats->fc.dropped_frames; |
295 | hstats->link_failure_count = fcstats->fc.link_failures; |
296 | hstats->loss_of_sync_count = fcstats->fc.loss_of_syncs; |
297 | hstats->loss_of_signal_count = fcstats->fc.loss_of_signals; |
298 | hstats->prim_seq_protocol_err_count = fcstats->fc.primseq_errs; |
299 | hstats->invalid_crc_count = fcstats->fc.invalid_crcs; |
300 | |
301 | kfree(objp: fcstats); |
302 | return hstats; |
303 | } |
304 | |
305 | /* |
306 | * FC transport template entry, reset BFAD statistics. |
307 | */ |
308 | static void |
309 | bfad_im_reset_stats(struct Scsi_Host *shost) |
310 | { |
311 | struct bfad_im_port_s *im_port = |
312 | (struct bfad_im_port_s *) shost->hostdata[0]; |
313 | struct bfad_s *bfad = im_port->bfad; |
314 | struct bfad_hal_comp fcomp; |
315 | unsigned long flags; |
316 | bfa_status_t rc; |
317 | |
318 | init_completion(x: &fcomp.comp); |
319 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
320 | rc = bfa_port_clear_stats(BFA_FCPORT(&bfad->bfa), cbfn: bfad_hcb_comp, |
321 | cbarg: &fcomp); |
322 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
323 | |
324 | if (rc != BFA_STATUS_OK) |
325 | return; |
326 | |
327 | wait_for_completion(&fcomp.comp); |
328 | |
329 | return; |
330 | } |
331 | |
332 | /* |
333 | * FC transport template entry, set rport loss timeout. |
334 | * Update dev_loss_tmo based on the value pushed down by the stack |
335 | * In case it is lesser than path_tov of driver, set it to path_tov + 1 |
336 | * to ensure that the driver times out before the application |
337 | */ |
338 | static void |
339 | bfad_im_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout) |
340 | { |
341 | struct bfad_itnim_data_s *itnim_data = rport->dd_data; |
342 | struct bfad_itnim_s *itnim = itnim_data->itnim; |
343 | struct bfad_s *bfad = itnim->im->bfad; |
344 | uint16_t path_tov = bfa_fcpim_path_tov_get(bfa: &bfad->bfa); |
345 | |
346 | rport->dev_loss_tmo = timeout; |
347 | if (timeout < path_tov) |
348 | rport->dev_loss_tmo = path_tov + 1; |
349 | } |
350 | |
351 | static int |
352 | bfad_im_vport_create(struct fc_vport *fc_vport, bool disable) |
353 | { |
354 | char *vname = fc_vport->symbolic_name; |
355 | struct Scsi_Host *shost = fc_vport->shost; |
356 | struct bfad_im_port_s *im_port = |
357 | (struct bfad_im_port_s *) shost->hostdata[0]; |
358 | struct bfad_s *bfad = im_port->bfad; |
359 | struct bfa_lport_cfg_s port_cfg; |
360 | struct bfad_vport_s *vp; |
361 | int status = 0, rc; |
362 | unsigned long flags; |
363 | |
364 | memset(&port_cfg, 0, sizeof(port_cfg)); |
365 | u64_to_wwn(inm: fc_vport->node_name, wwn: (u8 *)&port_cfg.nwwn); |
366 | u64_to_wwn(inm: fc_vport->port_name, wwn: (u8 *)&port_cfg.pwwn); |
367 | if (strlen(vname) > 0) |
368 | strcpy(p: (char *)&port_cfg.sym_name, q: vname); |
369 | port_cfg.roles = BFA_LPORT_ROLE_FCP_IM; |
370 | |
371 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
372 | list_for_each_entry(vp, &bfad->pbc_vport_list, list_entry) { |
373 | if (port_cfg.pwwn == |
374 | vp->fcs_vport.lport.port_cfg.pwwn) { |
375 | port_cfg.preboot_vp = |
376 | vp->fcs_vport.lport.port_cfg.preboot_vp; |
377 | break; |
378 | } |
379 | } |
380 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
381 | |
382 | rc = bfad_vport_create(bfad, vf_id: 0, port_cfg: &port_cfg, dev: &fc_vport->dev); |
383 | if (rc == BFA_STATUS_OK) { |
384 | struct bfad_vport_s *vport; |
385 | struct bfa_fcs_vport_s *fcs_vport; |
386 | struct Scsi_Host *vshost; |
387 | |
388 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
389 | fcs_vport = bfa_fcs_vport_lookup(fcs: &bfad->bfa_fcs, vf_id: 0, |
390 | vpwwn: port_cfg.pwwn); |
391 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
392 | if (fcs_vport == NULL) |
393 | return VPCERR_BAD_WWN; |
394 | |
395 | fc_vport_set_state(vport: fc_vport, new_state: FC_VPORT_ACTIVE); |
396 | if (disable) { |
397 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
398 | bfa_fcs_vport_stop(vport: fcs_vport); |
399 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
400 | fc_vport_set_state(vport: fc_vport, new_state: FC_VPORT_DISABLED); |
401 | } |
402 | |
403 | vport = fcs_vport->vport_drv; |
404 | vshost = vport->drv_port.im_port->shost; |
405 | fc_host_node_name(vshost) = wwn_to_u64(wwn: (u8 *)&port_cfg.nwwn); |
406 | fc_host_port_name(vshost) = wwn_to_u64(wwn: (u8 *)&port_cfg.pwwn); |
407 | fc_host_supported_classes(vshost) = FC_COS_CLASS3; |
408 | |
409 | memset(fc_host_supported_fc4s(vshost), 0, |
410 | sizeof(fc_host_supported_fc4s(vshost))); |
411 | |
412 | /* For FCP type 0x08 */ |
413 | if (supported_fc4s & BFA_LPORT_ROLE_FCP_IM) |
414 | fc_host_supported_fc4s(vshost)[2] = 1; |
415 | |
416 | /* For fibre channel services type 0x20 */ |
417 | fc_host_supported_fc4s(vshost)[7] = 1; |
418 | |
419 | fc_host_supported_speeds(vshost) = |
420 | bfad_im_supported_speeds(bfa: &bfad->bfa); |
421 | fc_host_maxframe_size(vshost) = |
422 | bfa_fcport_get_maxfrsize(bfa: &bfad->bfa); |
423 | |
424 | fc_vport->dd_data = vport; |
425 | vport->drv_port.im_port->fc_vport = fc_vport; |
426 | } else if (rc == BFA_STATUS_INVALID_WWN) |
427 | return VPCERR_BAD_WWN; |
428 | else if (rc == BFA_STATUS_VPORT_EXISTS) |
429 | return VPCERR_BAD_WWN; |
430 | else if (rc == BFA_STATUS_VPORT_MAX) |
431 | return VPCERR_NO_FABRIC_SUPP; |
432 | else if (rc == BFA_STATUS_VPORT_WWN_BP) |
433 | return VPCERR_BAD_WWN; |
434 | else |
435 | return FC_VPORT_FAILED; |
436 | |
437 | return status; |
438 | } |
439 | |
440 | static int |
441 | bfad_im_issue_fc_host_lip(struct Scsi_Host *shost) |
442 | { |
443 | struct bfad_im_port_s *im_port = |
444 | (struct bfad_im_port_s *) shost->hostdata[0]; |
445 | struct bfad_s *bfad = im_port->bfad; |
446 | struct bfad_hal_comp fcomp; |
447 | unsigned long flags; |
448 | uint32_t status; |
449 | |
450 | init_completion(x: &fcomp.comp); |
451 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
452 | status = bfa_port_disable(port: &bfad->bfa.modules.port, |
453 | cbfn: bfad_hcb_comp, cbarg: &fcomp); |
454 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
455 | |
456 | if (status != BFA_STATUS_OK) |
457 | return -EIO; |
458 | |
459 | wait_for_completion(&fcomp.comp); |
460 | if (fcomp.status != BFA_STATUS_OK) |
461 | return -EIO; |
462 | |
463 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
464 | status = bfa_port_enable(port: &bfad->bfa.modules.port, |
465 | cbfn: bfad_hcb_comp, cbarg: &fcomp); |
466 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
467 | if (status != BFA_STATUS_OK) |
468 | return -EIO; |
469 | |
470 | wait_for_completion(&fcomp.comp); |
471 | if (fcomp.status != BFA_STATUS_OK) |
472 | return -EIO; |
473 | |
474 | return 0; |
475 | } |
476 | |
477 | static int |
478 | bfad_im_vport_delete(struct fc_vport *fc_vport) |
479 | { |
480 | struct bfad_vport_s *vport = (struct bfad_vport_s *)fc_vport->dd_data; |
481 | struct bfad_im_port_s *im_port = |
482 | (struct bfad_im_port_s *) vport->drv_port.im_port; |
483 | struct bfad_s *bfad = im_port->bfad; |
484 | struct bfa_fcs_vport_s *fcs_vport; |
485 | struct Scsi_Host *vshost; |
486 | wwn_t pwwn; |
487 | int rc; |
488 | unsigned long flags; |
489 | struct completion fcomp; |
490 | |
491 | if (im_port->flags & BFAD_PORT_DELETE) { |
492 | bfad_scsi_host_free(bfad, im_port); |
493 | list_del(entry: &vport->list_entry); |
494 | kfree(objp: vport); |
495 | return 0; |
496 | } |
497 | |
498 | vshost = vport->drv_port.im_port->shost; |
499 | u64_to_wwn(fc_host_port_name(vshost), wwn: (u8 *)&pwwn); |
500 | |
501 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
502 | fcs_vport = bfa_fcs_vport_lookup(fcs: &bfad->bfa_fcs, vf_id: 0, vpwwn: pwwn); |
503 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
504 | |
505 | if (fcs_vport == NULL) |
506 | return VPCERR_BAD_WWN; |
507 | |
508 | vport->drv_port.flags |= BFAD_PORT_DELETE; |
509 | |
510 | vport->comp_del = &fcomp; |
511 | init_completion(x: vport->comp_del); |
512 | |
513 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
514 | rc = bfa_fcs_vport_delete(vport: &vport->fcs_vport); |
515 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
516 | |
517 | if (rc == BFA_STATUS_PBC) { |
518 | vport->drv_port.flags &= ~BFAD_PORT_DELETE; |
519 | vport->comp_del = NULL; |
520 | return -1; |
521 | } |
522 | |
523 | wait_for_completion(vport->comp_del); |
524 | |
525 | bfad_scsi_host_free(bfad, im_port); |
526 | list_del(entry: &vport->list_entry); |
527 | kfree(objp: vport); |
528 | |
529 | return 0; |
530 | } |
531 | |
532 | static int |
533 | bfad_im_vport_disable(struct fc_vport *fc_vport, bool disable) |
534 | { |
535 | struct bfad_vport_s *vport; |
536 | struct bfad_s *bfad; |
537 | struct bfa_fcs_vport_s *fcs_vport; |
538 | struct Scsi_Host *vshost; |
539 | wwn_t pwwn; |
540 | unsigned long flags; |
541 | |
542 | vport = (struct bfad_vport_s *)fc_vport->dd_data; |
543 | bfad = vport->drv_port.bfad; |
544 | vshost = vport->drv_port.im_port->shost; |
545 | u64_to_wwn(fc_host_port_name(vshost), wwn: (u8 *)&pwwn); |
546 | |
547 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
548 | fcs_vport = bfa_fcs_vport_lookup(fcs: &bfad->bfa_fcs, vf_id: 0, vpwwn: pwwn); |
549 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
550 | |
551 | if (fcs_vport == NULL) |
552 | return VPCERR_BAD_WWN; |
553 | |
554 | if (disable) { |
555 | bfa_fcs_vport_stop(vport: fcs_vport); |
556 | fc_vport_set_state(vport: fc_vport, new_state: FC_VPORT_DISABLED); |
557 | } else { |
558 | bfa_fcs_vport_start(vport: fcs_vport); |
559 | fc_vport_set_state(vport: fc_vport, new_state: FC_VPORT_ACTIVE); |
560 | } |
561 | |
562 | return 0; |
563 | } |
564 | |
565 | static void |
566 | bfad_im_vport_set_symbolic_name(struct fc_vport *fc_vport) |
567 | { |
568 | struct bfad_vport_s *vport = (struct bfad_vport_s *)fc_vport->dd_data; |
569 | struct bfad_im_port_s *im_port = |
570 | (struct bfad_im_port_s *)vport->drv_port.im_port; |
571 | struct bfad_s *bfad = im_port->bfad; |
572 | struct Scsi_Host *vshost = vport->drv_port.im_port->shost; |
573 | char *sym_name = fc_vport->symbolic_name; |
574 | struct bfa_fcs_vport_s *fcs_vport; |
575 | wwn_t pwwn; |
576 | unsigned long flags; |
577 | |
578 | u64_to_wwn(fc_host_port_name(vshost), wwn: (u8 *)&pwwn); |
579 | |
580 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
581 | fcs_vport = bfa_fcs_vport_lookup(fcs: &bfad->bfa_fcs, vf_id: 0, vpwwn: pwwn); |
582 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
583 | |
584 | if (fcs_vport == NULL) |
585 | return; |
586 | |
587 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
588 | if (strlen(sym_name) > 0) |
589 | bfa_fcs_lport_set_symname(port: &fcs_vport->lport, symname: sym_name); |
590 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
591 | } |
592 | |
593 | struct fc_function_template bfad_im_fc_function_template = { |
594 | |
595 | /* Target dynamic attributes */ |
596 | .get_starget_port_id = bfad_im_get_starget_port_id, |
597 | .show_starget_port_id = 1, |
598 | .get_starget_node_name = bfad_im_get_starget_node_name, |
599 | .show_starget_node_name = 1, |
600 | .get_starget_port_name = bfad_im_get_starget_port_name, |
601 | .show_starget_port_name = 1, |
602 | |
603 | /* Host dynamic attribute */ |
604 | .get_host_port_id = bfad_im_get_host_port_id, |
605 | .show_host_port_id = 1, |
606 | |
607 | /* Host fixed attributes */ |
608 | .show_host_node_name = 1, |
609 | .show_host_port_name = 1, |
610 | .show_host_supported_classes = 1, |
611 | .show_host_supported_fc4s = 1, |
612 | .show_host_supported_speeds = 1, |
613 | .show_host_maxframe_size = 1, |
614 | |
615 | /* More host dynamic attributes */ |
616 | .show_host_port_type = 1, |
617 | .get_host_port_type = bfad_im_get_host_port_type, |
618 | .show_host_port_state = 1, |
619 | .get_host_port_state = bfad_im_get_host_port_state, |
620 | .show_host_active_fc4s = 1, |
621 | .get_host_active_fc4s = bfad_im_get_host_active_fc4s, |
622 | .show_host_speed = 1, |
623 | .get_host_speed = bfad_im_get_host_speed, |
624 | .show_host_fabric_name = 1, |
625 | .get_host_fabric_name = bfad_im_get_host_fabric_name, |
626 | |
627 | .show_host_symbolic_name = 1, |
628 | |
629 | /* Statistics */ |
630 | .get_fc_host_stats = bfad_im_get_stats, |
631 | .reset_fc_host_stats = bfad_im_reset_stats, |
632 | |
633 | /* Allocation length for host specific data */ |
634 | .dd_fcrport_size = sizeof(struct bfad_itnim_data_s *), |
635 | |
636 | /* Remote port fixed attributes */ |
637 | .show_rport_maxframe_size = 1, |
638 | .show_rport_supported_classes = 1, |
639 | .show_rport_dev_loss_tmo = 1, |
640 | .set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo, |
641 | .issue_fc_host_lip = bfad_im_issue_fc_host_lip, |
642 | .vport_create = bfad_im_vport_create, |
643 | .vport_delete = bfad_im_vport_delete, |
644 | .vport_disable = bfad_im_vport_disable, |
645 | .set_vport_symbolic_name = bfad_im_vport_set_symbolic_name, |
646 | .bsg_request = bfad_im_bsg_request, |
647 | .bsg_timeout = bfad_im_bsg_timeout, |
648 | }; |
649 | |
650 | struct fc_function_template bfad_im_vport_fc_function_template = { |
651 | |
652 | /* Target dynamic attributes */ |
653 | .get_starget_port_id = bfad_im_get_starget_port_id, |
654 | .show_starget_port_id = 1, |
655 | .get_starget_node_name = bfad_im_get_starget_node_name, |
656 | .show_starget_node_name = 1, |
657 | .get_starget_port_name = bfad_im_get_starget_port_name, |
658 | .show_starget_port_name = 1, |
659 | |
660 | /* Host dynamic attribute */ |
661 | .get_host_port_id = bfad_im_get_host_port_id, |
662 | .show_host_port_id = 1, |
663 | |
664 | /* Host fixed attributes */ |
665 | .show_host_node_name = 1, |
666 | .show_host_port_name = 1, |
667 | .show_host_supported_classes = 1, |
668 | .show_host_supported_fc4s = 1, |
669 | .show_host_supported_speeds = 1, |
670 | .show_host_maxframe_size = 1, |
671 | |
672 | /* More host dynamic attributes */ |
673 | .show_host_port_type = 1, |
674 | .get_host_port_type = bfad_im_get_host_port_type, |
675 | .show_host_port_state = 1, |
676 | .get_host_port_state = bfad_im_get_host_port_state, |
677 | .show_host_active_fc4s = 1, |
678 | .get_host_active_fc4s = bfad_im_get_host_active_fc4s, |
679 | .show_host_speed = 1, |
680 | .get_host_speed = bfad_im_get_host_speed, |
681 | .show_host_fabric_name = 1, |
682 | .get_host_fabric_name = bfad_im_get_host_fabric_name, |
683 | |
684 | .show_host_symbolic_name = 1, |
685 | |
686 | /* Statistics */ |
687 | .get_fc_host_stats = bfad_im_get_stats, |
688 | .reset_fc_host_stats = bfad_im_reset_stats, |
689 | |
690 | /* Allocation length for host specific data */ |
691 | .dd_fcrport_size = sizeof(struct bfad_itnim_data_s *), |
692 | |
693 | /* Remote port fixed attributes */ |
694 | .show_rport_maxframe_size = 1, |
695 | .show_rport_supported_classes = 1, |
696 | .show_rport_dev_loss_tmo = 1, |
697 | .set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo, |
698 | }; |
699 | |
700 | /* |
701 | * Scsi_Host_attrs SCSI host attributes |
702 | */ |
703 | static ssize_t |
704 | bfad_im_serial_num_show(struct device *dev, struct device_attribute *attr, |
705 | char *buf) |
706 | { |
707 | struct Scsi_Host *shost = class_to_shost(dev); |
708 | struct bfad_im_port_s *im_port = |
709 | (struct bfad_im_port_s *) shost->hostdata[0]; |
710 | struct bfad_s *bfad = im_port->bfad; |
711 | char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN]; |
712 | |
713 | bfa_get_adapter_serial_num(&bfad->bfa, serial_num); |
714 | return sysfs_emit(buf, fmt: "%s\n" , serial_num); |
715 | } |
716 | |
717 | static ssize_t |
718 | bfad_im_model_show(struct device *dev, struct device_attribute *attr, |
719 | char *buf) |
720 | { |
721 | struct Scsi_Host *shost = class_to_shost(dev); |
722 | struct bfad_im_port_s *im_port = |
723 | (struct bfad_im_port_s *) shost->hostdata[0]; |
724 | struct bfad_s *bfad = im_port->bfad; |
725 | char model[BFA_ADAPTER_MODEL_NAME_LEN]; |
726 | |
727 | bfa_get_adapter_model(&bfad->bfa, model); |
728 | return sysfs_emit(buf, fmt: "%s\n" , model); |
729 | } |
730 | |
731 | static ssize_t |
732 | bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr, |
733 | char *buf) |
734 | { |
735 | struct Scsi_Host *shost = class_to_shost(dev); |
736 | struct bfad_im_port_s *im_port = |
737 | (struct bfad_im_port_s *) shost->hostdata[0]; |
738 | struct bfad_s *bfad = im_port->bfad; |
739 | char model[BFA_ADAPTER_MODEL_NAME_LEN]; |
740 | char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN]; |
741 | int nports = 0; |
742 | |
743 | bfa_get_adapter_model(&bfad->bfa, model); |
744 | nports = bfa_get_nports(&bfad->bfa); |
745 | if (!strcmp(model, "QLogic-425" )) |
746 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
747 | fmt: "QLogic BR-series 4Gbps PCIe dual port FC HBA" ); |
748 | else if (!strcmp(model, "QLogic-825" )) |
749 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
750 | fmt: "QLogic BR-series 8Gbps PCIe dual port FC HBA" ); |
751 | else if (!strcmp(model, "QLogic-42B" )) |
752 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
753 | fmt: "QLogic BR-series 4Gbps PCIe dual port FC HBA for HP" ); |
754 | else if (!strcmp(model, "QLogic-82B" )) |
755 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
756 | fmt: "QLogic BR-series 8Gbps PCIe dual port FC HBA for HP" ); |
757 | else if (!strcmp(model, "QLogic-1010" )) |
758 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
759 | fmt: "QLogic BR-series 10Gbps single port CNA" ); |
760 | else if (!strcmp(model, "QLogic-1020" )) |
761 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
762 | fmt: "QLogic BR-series 10Gbps dual port CNA" ); |
763 | else if (!strcmp(model, "QLogic-1007" )) |
764 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
765 | fmt: "QLogic BR-series 10Gbps CNA for IBM Blade Center" ); |
766 | else if (!strcmp(model, "QLogic-415" )) |
767 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
768 | fmt: "QLogic BR-series 4Gbps PCIe single port FC HBA" ); |
769 | else if (!strcmp(model, "QLogic-815" )) |
770 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
771 | fmt: "QLogic BR-series 8Gbps PCIe single port FC HBA" ); |
772 | else if (!strcmp(model, "QLogic-41B" )) |
773 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
774 | fmt: "QLogic BR-series 4Gbps PCIe single port FC HBA for HP" ); |
775 | else if (!strcmp(model, "QLogic-81B" )) |
776 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
777 | fmt: "QLogic BR-series 8Gbps PCIe single port FC HBA for HP" ); |
778 | else if (!strcmp(model, "QLogic-804" )) |
779 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
780 | fmt: "QLogic BR-series 8Gbps FC HBA for HP Bladesystem C-class" ); |
781 | else if (!strcmp(model, "QLogic-1741" )) |
782 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
783 | fmt: "QLogic BR-series 10Gbps CNA for Dell M-Series Blade Servers" ); |
784 | else if (strstr(model, "QLogic-1860" )) { |
785 | if (nports == 1 && bfa_ioc_is_cna(&bfad->bfa.ioc)) |
786 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
787 | fmt: "QLogic BR-series 10Gbps single port CNA" ); |
788 | else if (nports == 1 && !bfa_ioc_is_cna(&bfad->bfa.ioc)) |
789 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
790 | fmt: "QLogic BR-series 16Gbps PCIe single port FC HBA" ); |
791 | else if (nports == 2 && bfa_ioc_is_cna(&bfad->bfa.ioc)) |
792 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
793 | fmt: "QLogic BR-series 10Gbps dual port CNA" ); |
794 | else if (nports == 2 && !bfa_ioc_is_cna(&bfad->bfa.ioc)) |
795 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
796 | fmt: "QLogic BR-series 16Gbps PCIe dual port FC HBA" ); |
797 | } else if (!strcmp(model, "QLogic-1867" )) { |
798 | if (nports == 1 && !bfa_ioc_is_cna(&bfad->bfa.ioc)) |
799 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
800 | fmt: "QLogic BR-series 16Gbps PCIe single port FC HBA for IBM" ); |
801 | else if (nports == 2 && !bfa_ioc_is_cna(&bfad->bfa.ioc)) |
802 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
803 | fmt: "QLogic BR-series 16Gbps PCIe dual port FC HBA for IBM" ); |
804 | } else |
805 | snprintf(buf: model_descr, size: BFA_ADAPTER_MODEL_DESCR_LEN, |
806 | fmt: "Invalid Model" ); |
807 | |
808 | return sysfs_emit(buf, fmt: "%s\n" , model_descr); |
809 | } |
810 | |
811 | static ssize_t |
812 | bfad_im_node_name_show(struct device *dev, struct device_attribute *attr, |
813 | char *buf) |
814 | { |
815 | struct Scsi_Host *shost = class_to_shost(dev); |
816 | struct bfad_im_port_s *im_port = |
817 | (struct bfad_im_port_s *) shost->hostdata[0]; |
818 | struct bfad_port_s *port = im_port->port; |
819 | u64 nwwn; |
820 | |
821 | nwwn = bfa_fcs_lport_get_nwwn(port->fcs_port); |
822 | return sysfs_emit(buf, fmt: "0x%llx\n" , cpu_to_be64(nwwn)); |
823 | } |
824 | |
825 | static ssize_t |
826 | bfad_im_symbolic_name_show(struct device *dev, struct device_attribute *attr, |
827 | char *buf) |
828 | { |
829 | struct Scsi_Host *shost = class_to_shost(dev); |
830 | struct bfad_im_port_s *im_port = |
831 | (struct bfad_im_port_s *) shost->hostdata[0]; |
832 | struct bfad_s *bfad = im_port->bfad; |
833 | struct bfa_lport_attr_s port_attr; |
834 | char symname[BFA_SYMNAME_MAXLEN]; |
835 | |
836 | bfa_fcs_lport_get_attr(port: &bfad->bfa_fcs.fabric.bport, port_attr: &port_attr); |
837 | strscpy(p: symname, q: port_attr.port_cfg.sym_name.symname, |
838 | BFA_SYMNAME_MAXLEN); |
839 | return sysfs_emit(buf, fmt: "%s\n" , symname); |
840 | } |
841 | |
842 | static ssize_t |
843 | bfad_im_hw_version_show(struct device *dev, struct device_attribute *attr, |
844 | char *buf) |
845 | { |
846 | struct Scsi_Host *shost = class_to_shost(dev); |
847 | struct bfad_im_port_s *im_port = |
848 | (struct bfad_im_port_s *) shost->hostdata[0]; |
849 | struct bfad_s *bfad = im_port->bfad; |
850 | char hw_ver[BFA_VERSION_LEN]; |
851 | |
852 | bfa_get_pci_chip_rev(&bfad->bfa, hw_ver); |
853 | return sysfs_emit(buf, fmt: "%s\n" , hw_ver); |
854 | } |
855 | |
856 | static ssize_t |
857 | bfad_im_drv_version_show(struct device *dev, struct device_attribute *attr, |
858 | char *buf) |
859 | { |
860 | return sysfs_emit(buf, fmt: "%s\n" , BFAD_DRIVER_VERSION); |
861 | } |
862 | |
863 | static ssize_t |
864 | bfad_im_optionrom_version_show(struct device *dev, |
865 | struct device_attribute *attr, char *buf) |
866 | { |
867 | struct Scsi_Host *shost = class_to_shost(dev); |
868 | struct bfad_im_port_s *im_port = |
869 | (struct bfad_im_port_s *) shost->hostdata[0]; |
870 | struct bfad_s *bfad = im_port->bfad; |
871 | char optrom_ver[BFA_VERSION_LEN]; |
872 | |
873 | bfa_get_adapter_optrom_ver(&bfad->bfa, optrom_ver); |
874 | return sysfs_emit(buf, fmt: "%s\n" , optrom_ver); |
875 | } |
876 | |
877 | static ssize_t |
878 | bfad_im_fw_version_show(struct device *dev, struct device_attribute *attr, |
879 | char *buf) |
880 | { |
881 | struct Scsi_Host *shost = class_to_shost(dev); |
882 | struct bfad_im_port_s *im_port = |
883 | (struct bfad_im_port_s *) shost->hostdata[0]; |
884 | struct bfad_s *bfad = im_port->bfad; |
885 | char fw_ver[BFA_VERSION_LEN]; |
886 | |
887 | bfa_get_adapter_fw_ver(&bfad->bfa, fw_ver); |
888 | return sysfs_emit(buf, fmt: "%s\n" , fw_ver); |
889 | } |
890 | |
891 | static ssize_t |
892 | bfad_im_num_of_ports_show(struct device *dev, struct device_attribute *attr, |
893 | char *buf) |
894 | { |
895 | struct Scsi_Host *shost = class_to_shost(dev); |
896 | struct bfad_im_port_s *im_port = |
897 | (struct bfad_im_port_s *) shost->hostdata[0]; |
898 | struct bfad_s *bfad = im_port->bfad; |
899 | |
900 | return sysfs_emit(buf, fmt: "%d\n" , |
901 | bfa_get_nports(&bfad->bfa)); |
902 | } |
903 | |
904 | static ssize_t |
905 | bfad_im_drv_name_show(struct device *dev, struct device_attribute *attr, |
906 | char *buf) |
907 | { |
908 | return sysfs_emit(buf, fmt: "%s\n" , BFAD_DRIVER_NAME); |
909 | } |
910 | |
911 | static ssize_t |
912 | bfad_im_num_of_discovered_ports_show(struct device *dev, |
913 | struct device_attribute *attr, char *buf) |
914 | { |
915 | struct Scsi_Host *shost = class_to_shost(dev); |
916 | struct bfad_im_port_s *im_port = |
917 | (struct bfad_im_port_s *) shost->hostdata[0]; |
918 | struct bfad_port_s *port = im_port->port; |
919 | struct bfad_s *bfad = im_port->bfad; |
920 | int nrports = 2048; |
921 | struct bfa_rport_qualifier_s *rports = NULL; |
922 | unsigned long flags; |
923 | |
924 | rports = kcalloc(n: nrports, size: sizeof(struct bfa_rport_qualifier_s), |
925 | GFP_ATOMIC); |
926 | if (rports == NULL) |
927 | return sysfs_emit(buf, fmt: "Failed\n" ); |
928 | |
929 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
930 | bfa_fcs_lport_get_rport_quals(port: port->fcs_port, rport: rports, nrports: &nrports); |
931 | spin_unlock_irqrestore(lock: &bfad->bfad_lock, flags); |
932 | kfree(objp: rports); |
933 | |
934 | return sysfs_emit(buf, fmt: "%d\n" , nrports); |
935 | } |
936 | |
937 | static DEVICE_ATTR(serial_number, S_IRUGO, |
938 | bfad_im_serial_num_show, NULL); |
939 | static DEVICE_ATTR(model, S_IRUGO, bfad_im_model_show, NULL); |
940 | static DEVICE_ATTR(model_description, S_IRUGO, |
941 | bfad_im_model_desc_show, NULL); |
942 | static DEVICE_ATTR(node_name, S_IRUGO, bfad_im_node_name_show, NULL); |
943 | static DEVICE_ATTR(symbolic_name, S_IRUGO, |
944 | bfad_im_symbolic_name_show, NULL); |
945 | static DEVICE_ATTR(hardware_version, S_IRUGO, |
946 | bfad_im_hw_version_show, NULL); |
947 | static DEVICE_ATTR(driver_version, S_IRUGO, |
948 | bfad_im_drv_version_show, NULL); |
949 | static DEVICE_ATTR(option_rom_version, S_IRUGO, |
950 | bfad_im_optionrom_version_show, NULL); |
951 | static DEVICE_ATTR(firmware_version, S_IRUGO, |
952 | bfad_im_fw_version_show, NULL); |
953 | static DEVICE_ATTR(number_of_ports, S_IRUGO, |
954 | bfad_im_num_of_ports_show, NULL); |
955 | static DEVICE_ATTR(driver_name, S_IRUGO, bfad_im_drv_name_show, NULL); |
956 | static DEVICE_ATTR(number_of_discovered_ports, S_IRUGO, |
957 | bfad_im_num_of_discovered_ports_show, NULL); |
958 | |
959 | static struct attribute *bfad_im_host_attrs[] = { |
960 | &dev_attr_serial_number.attr, |
961 | &dev_attr_model.attr, |
962 | &dev_attr_model_description.attr, |
963 | &dev_attr_node_name.attr, |
964 | &dev_attr_symbolic_name.attr, |
965 | &dev_attr_hardware_version.attr, |
966 | &dev_attr_driver_version.attr, |
967 | &dev_attr_option_rom_version.attr, |
968 | &dev_attr_firmware_version.attr, |
969 | &dev_attr_number_of_ports.attr, |
970 | &dev_attr_driver_name.attr, |
971 | &dev_attr_number_of_discovered_ports.attr, |
972 | NULL, |
973 | }; |
974 | |
975 | static const struct attribute_group bfad_im_host_attr_group = { |
976 | .attrs = bfad_im_host_attrs |
977 | }; |
978 | |
979 | const struct attribute_group *bfad_im_host_groups[] = { |
980 | &bfad_im_host_attr_group, |
981 | NULL |
982 | }; |
983 | |
984 | static struct attribute *bfad_im_vport_attrs[] = { |
985 | &dev_attr_serial_number.attr, |
986 | &dev_attr_model.attr, |
987 | &dev_attr_model_description.attr, |
988 | &dev_attr_node_name.attr, |
989 | &dev_attr_symbolic_name.attr, |
990 | &dev_attr_hardware_version.attr, |
991 | &dev_attr_driver_version.attr, |
992 | &dev_attr_option_rom_version.attr, |
993 | &dev_attr_firmware_version.attr, |
994 | &dev_attr_number_of_ports.attr, |
995 | &dev_attr_driver_name.attr, |
996 | &dev_attr_number_of_discovered_ports.attr, |
997 | NULL, |
998 | }; |
999 | |
1000 | static const struct attribute_group bfad_im_vport_attr_group = { |
1001 | .attrs = bfad_im_vport_attrs |
1002 | }; |
1003 | |
1004 | const struct attribute_group *bfad_im_vport_groups[] = { |
1005 | &bfad_im_vport_attr_group, |
1006 | NULL |
1007 | }; |
1008 | |