Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. |
| 3 | * All rights reserved |
| 4 | * www.brocade.com |
| 5 | * |
| 6 | * Linux driver for Brocade Fibre Channel Host Bus Adapter. |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify it |
| 9 | * under the terms of the GNU General Public License (GPL) Version 2 as |
| 10 | * published by the Free Software Foundation |
| 11 | * |
| 12 | * This program is distributed in the hope that it will be useful, but |
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | * General Public License for more details. |
| 16 | */ |
| 17 | |
| 18 | /** |
| 19 | * port_api.c BFA FCS port |
| 20 | */ |
| 21 | |
| 22 | #include <fcs/bfa_fcs.h> |
| 23 | #include <fcs/bfa_fcs_lport.h> |
| 24 | #include <fcs/bfa_fcs_rport.h> |
| 25 | #include "fcs_rport.h" |
| 26 | #include "fcs_fabric.h" |
| 27 | #include "fcs_trcmod.h" |
| 28 | #include "fcs_vport.h" |
| 29 | |
| 30 | BFA_TRC_FILE(FCS, PORT_API); |
| 31 | |
| 32 | |
| 33 | |
| 34 | /** |
| 35 | * fcs_port_api BFA FCS port API |
| 36 | */ |
| 37 | |
| 38 | void |
| 39 | bfa_fcs_cfg_base_port(struct bfa_fcs_s *fcs, struct bfa_port_cfg_s *port_cfg) |
| 40 | { |
| 41 | } |
| 42 | |
| 43 | struct bfa_fcs_port_s * |
| 44 | bfa_fcs_get_base_port(struct bfa_fcs_s *fcs) |
| 45 | { |
Jing Huang | f8ceafd | 2009-09-25 12:29:54 -0700 | [diff] [blame] | 46 | return &fcs->fabric.bport; |
Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 47 | } |
| 48 | |
| 49 | wwn_t |
| 50 | bfa_fcs_port_get_rport(struct bfa_fcs_port_s *port, wwn_t wwn, int index, |
| 51 | int nrports, bfa_boolean_t bwwn) |
| 52 | { |
| 53 | struct list_head *qh, *qe; |
| 54 | struct bfa_fcs_rport_s *rport = NULL; |
| 55 | int i; |
| 56 | struct bfa_fcs_s *fcs; |
| 57 | |
| 58 | if (port == NULL || nrports == 0) |
| 59 | return (wwn_t) 0; |
| 60 | |
| 61 | fcs = port->fcs; |
| 62 | bfa_trc(fcs, (u32) nrports); |
| 63 | |
| 64 | i = 0; |
| 65 | qh = &port->rport_q; |
| 66 | qe = bfa_q_first(qh); |
| 67 | |
| 68 | while ((qe != qh) && (i < nrports)) { |
| 69 | rport = (struct bfa_fcs_rport_s *)qe; |
| 70 | if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) { |
| 71 | qe = bfa_q_next(qe); |
| 72 | bfa_trc(fcs, (u32) rport->pwwn); |
| 73 | bfa_trc(fcs, rport->pid); |
| 74 | bfa_trc(fcs, i); |
| 75 | continue; |
| 76 | } |
| 77 | |
| 78 | if (bwwn) { |
| 79 | if (!memcmp(&wwn, &rport->pwwn, 8)) |
| 80 | break; |
| 81 | } else { |
| 82 | if (i == index) |
| 83 | break; |
| 84 | } |
| 85 | |
| 86 | i++; |
| 87 | qe = bfa_q_next(qe); |
| 88 | } |
| 89 | |
| 90 | bfa_trc(fcs, i); |
Jing Huang | f8ceafd | 2009-09-25 12:29:54 -0700 | [diff] [blame] | 91 | if (rport) |
Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 92 | return rport->pwwn; |
Jing Huang | f8ceafd | 2009-09-25 12:29:54 -0700 | [diff] [blame] | 93 | else |
Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 94 | return (wwn_t) 0; |
Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 95 | } |
| 96 | |
| 97 | void |
| 98 | bfa_fcs_port_get_rports(struct bfa_fcs_port_s *port, wwn_t rport_wwns[], |
| 99 | int *nrports) |
| 100 | { |
| 101 | struct list_head *qh, *qe; |
| 102 | struct bfa_fcs_rport_s *rport = NULL; |
| 103 | int i; |
| 104 | struct bfa_fcs_s *fcs; |
| 105 | |
| 106 | if (port == NULL || rport_wwns == NULL || *nrports == 0) |
| 107 | return; |
| 108 | |
| 109 | fcs = port->fcs; |
| 110 | bfa_trc(fcs, (u32) *nrports); |
| 111 | |
| 112 | i = 0; |
| 113 | qh = &port->rport_q; |
| 114 | qe = bfa_q_first(qh); |
| 115 | |
| 116 | while ((qe != qh) && (i < *nrports)) { |
| 117 | rport = (struct bfa_fcs_rport_s *)qe; |
| 118 | if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) { |
| 119 | qe = bfa_q_next(qe); |
| 120 | bfa_trc(fcs, (u32) rport->pwwn); |
| 121 | bfa_trc(fcs, rport->pid); |
| 122 | bfa_trc(fcs, i); |
| 123 | continue; |
| 124 | } |
| 125 | |
| 126 | rport_wwns[i] = rport->pwwn; |
| 127 | |
| 128 | i++; |
| 129 | qe = bfa_q_next(qe); |
| 130 | } |
| 131 | |
| 132 | bfa_trc(fcs, i); |
| 133 | *nrports = i; |
| 134 | return; |
| 135 | } |
| 136 | |
| 137 | /* |
| 138 | * Iterate's through all the rport's in the given port to |
| 139 | * determine the maximum operating speed. |
| 140 | */ |
| 141 | enum bfa_pport_speed |
| 142 | bfa_fcs_port_get_rport_max_speed(struct bfa_fcs_port_s *port) |
| 143 | { |
| 144 | struct list_head *qh, *qe; |
| 145 | struct bfa_fcs_rport_s *rport = NULL; |
| 146 | struct bfa_fcs_s *fcs; |
| 147 | enum bfa_pport_speed max_speed = 0; |
| 148 | struct bfa_pport_attr_s pport_attr; |
| 149 | enum bfa_pport_speed pport_speed; |
| 150 | |
| 151 | if (port == NULL) |
| 152 | return 0; |
| 153 | |
| 154 | fcs = port->fcs; |
| 155 | |
| 156 | /* |
| 157 | * Get Physical port's current speed |
| 158 | */ |
| 159 | bfa_pport_get_attr(port->fcs->bfa, &pport_attr); |
| 160 | pport_speed = pport_attr.speed; |
| 161 | bfa_trc(fcs, pport_speed); |
| 162 | |
| 163 | qh = &port->rport_q; |
| 164 | qe = bfa_q_first(qh); |
| 165 | |
| 166 | while (qe != qh) { |
| 167 | rport = (struct bfa_fcs_rport_s *)qe; |
| 168 | if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000) |
| 169 | || (bfa_fcs_rport_get_state(rport) == BFA_RPORT_OFFLINE)) { |
| 170 | qe = bfa_q_next(qe); |
| 171 | continue; |
| 172 | } |
| 173 | |
| 174 | if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_8GBPS) |
| 175 | || (rport->rpf.rpsc_speed > pport_speed)) { |
| 176 | max_speed = rport->rpf.rpsc_speed; |
| 177 | break; |
| 178 | } else if (rport->rpf.rpsc_speed > max_speed) { |
| 179 | max_speed = rport->rpf.rpsc_speed; |
| 180 | } |
| 181 | |
| 182 | qe = bfa_q_next(qe); |
| 183 | } |
| 184 | |
| 185 | bfa_trc(fcs, max_speed); |
| 186 | return max_speed; |
| 187 | } |
| 188 | |
| 189 | struct bfa_fcs_port_s * |
| 190 | bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t lpwwn) |
| 191 | { |
| 192 | struct bfa_fcs_vport_s *vport; |
| 193 | bfa_fcs_vf_t *vf; |
| 194 | |
| 195 | bfa_assert(fcs != NULL); |
| 196 | |
| 197 | vf = bfa_fcs_vf_lookup(fcs, vf_id); |
| 198 | if (vf == NULL) { |
| 199 | bfa_trc(fcs, vf_id); |
Jing Huang | f8ceafd | 2009-09-25 12:29:54 -0700 | [diff] [blame] | 200 | return NULL; |
Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 201 | } |
| 202 | |
| 203 | if (!lpwwn || (vf->bport.port_cfg.pwwn == lpwwn)) |
Jing Huang | f8ceafd | 2009-09-25 12:29:54 -0700 | [diff] [blame] | 204 | return &vf->bport; |
Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 205 | |
| 206 | vport = bfa_fcs_fabric_vport_lookup(vf, lpwwn); |
| 207 | if (vport) |
Jing Huang | f8ceafd | 2009-09-25 12:29:54 -0700 | [diff] [blame] | 208 | return &vport->lport; |
Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 209 | |
Jing Huang | f8ceafd | 2009-09-25 12:29:54 -0700 | [diff] [blame] | 210 | return NULL; |
Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 211 | } |
| 212 | |
| 213 | /* |
| 214 | * API corresponding to VmWare's NPIV_VPORT_GETINFO. |
| 215 | */ |
| 216 | void |
| 217 | bfa_fcs_port_get_info(struct bfa_fcs_port_s *port, |
| 218 | struct bfa_port_info_s *port_info) |
| 219 | { |
| 220 | |
| 221 | bfa_trc(port->fcs, port->fabric->fabric_name); |
| 222 | |
| 223 | if (port->vport == NULL) { |
| 224 | /* |
| 225 | * This is a Physical port |
| 226 | */ |
| 227 | port_info->port_type = BFA_PORT_TYPE_PHYSICAL; |
| 228 | |
| 229 | /* |
| 230 | * @todo : need to fix the state & reason |
| 231 | */ |
| 232 | port_info->port_state = 0; |
| 233 | port_info->offline_reason = 0; |
| 234 | |
| 235 | port_info->port_wwn = bfa_fcs_port_get_pwwn(port); |
| 236 | port_info->node_wwn = bfa_fcs_port_get_nwwn(port); |
| 237 | |
| 238 | port_info->max_vports_supp = bfa_fcs_vport_get_max(port->fcs); |
| 239 | port_info->num_vports_inuse = |
| 240 | bfa_fcs_fabric_vport_count(port->fabric); |
| 241 | port_info->max_rports_supp = BFA_FCS_MAX_RPORTS_SUPP; |
| 242 | port_info->num_rports_inuse = port->num_rports; |
| 243 | } else { |
| 244 | /* |
| 245 | * This is a virtual port |
| 246 | */ |
| 247 | port_info->port_type = BFA_PORT_TYPE_VIRTUAL; |
| 248 | |
| 249 | /* |
| 250 | * @todo : need to fix the state & reason |
| 251 | */ |
| 252 | port_info->port_state = 0; |
| 253 | port_info->offline_reason = 0; |
| 254 | |
| 255 | port_info->port_wwn = bfa_fcs_port_get_pwwn(port); |
| 256 | port_info->node_wwn = bfa_fcs_port_get_nwwn(port); |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | void |
| 261 | bfa_fcs_port_get_stats(struct bfa_fcs_port_s *fcs_port, |
| 262 | struct bfa_port_stats_s *port_stats) |
| 263 | { |
| 264 | bfa_os_memcpy(port_stats, &fcs_port->stats, |
| 265 | sizeof(struct bfa_port_stats_s)); |
| 266 | return; |
| 267 | } |
| 268 | |
| 269 | void |
| 270 | bfa_fcs_port_clear_stats(struct bfa_fcs_port_s *fcs_port) |
| 271 | { |
| 272 | bfa_os_memset(&fcs_port->stats, 0, sizeof(struct bfa_port_stats_s)); |
| 273 | return; |
| 274 | } |
| 275 | |
| 276 | void |
| 277 | bfa_fcs_port_enable_ipfc_roles(struct bfa_fcs_port_s *fcs_port) |
| 278 | { |
| 279 | fcs_port->port_cfg.roles |= BFA_PORT_ROLE_FCP_IPFC; |
| 280 | return; |
| 281 | } |
| 282 | |
| 283 | void |
| 284 | bfa_fcs_port_disable_ipfc_roles(struct bfa_fcs_port_s *fcs_port) |
| 285 | { |
| 286 | fcs_port->port_cfg.roles &= ~BFA_PORT_ROLE_FCP_IPFC; |
| 287 | return; |
| 288 | } |
| 289 | |
| 290 | |