1 /* 2 * Copyright (c) 2005-2010 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 #include "bfa_defs_svc.h" 19 #include "bfa_port.h" 20 #include "bfi.h" 21 #include "bfa_ioc.h" 22 23 24 BFA_TRC_FILE(CNA, PORT); 25 26 #define bfa_ioc_portid(__ioc) ((__ioc)->port_id) 27 28 static void 29 bfa_port_stats_swap(struct bfa_port_s *port, union bfa_port_stats_u *stats) 30 { 31 u32 *dip = (u32 *) stats; 32 u32 t0, t1; 33 int i; 34 35 for (i = 0; i < sizeof(union bfa_port_stats_u)/sizeof(u32); 36 i += 2) { 37 t0 = dip[i]; 38 t1 = dip[i + 1]; 39 #ifdef __BIGENDIAN 40 dip[i] = be32_to_cpu(t0); 41 dip[i + 1] = be32_to_cpu(t1); 42 #else 43 dip[i] = be32_to_cpu(t1); 44 dip[i + 1] = be32_to_cpu(t0); 45 #endif 46 } 47 } 48 49 /* 50 * bfa_port_enable_isr() 51 * 52 * 53 * @param[in] port - Pointer to the port module 54 * status - Return status from the f/w 55 * 56 * @return void 57 */ 58 static void 59 bfa_port_enable_isr(struct bfa_port_s *port, bfa_status_t status) 60 { 61 bfa_trc(port, status); 62 port->endis_pending = BFA_FALSE; 63 port->endis_cbfn(port->endis_cbarg, status); 64 } 65 66 /* 67 * bfa_port_disable_isr() 68 * 69 * 70 * @param[in] port - Pointer to the port module 71 * status - Return status from the f/w 72 * 73 * @return void 74 */ 75 static void 76 bfa_port_disable_isr(struct bfa_port_s *port, bfa_status_t status) 77 { 78 bfa_trc(port, status); 79 port->endis_pending = BFA_FALSE; 80 port->endis_cbfn(port->endis_cbarg, status); 81 } 82 83 /* 84 * bfa_port_get_stats_isr() 85 * 86 * 87 * @param[in] port - Pointer to the Port module 88 * status - Return status from the f/w 89 * 90 * @return void 91 */ 92 static void 93 bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status) 94 { 95 port->stats_status = status; 96 port->stats_busy = BFA_FALSE; 97 98 if (status == BFA_STATUS_OK) { 99 struct bfa_timeval_s tv; 100 101 memcpy(port->stats, port->stats_dma.kva, 102 sizeof(union bfa_port_stats_u)); 103 bfa_port_stats_swap(port, port->stats); 104 105 bfa_os_gettimeofday(&tv); 106 port->stats->fc.secs_reset = tv.tv_sec - port->stats_reset_time; 107 } 108 109 if (port->stats_cbfn) { 110 port->stats_cbfn(port->stats_cbarg, status); 111 port->stats_cbfn = NULL; 112 } 113 } 114 115 /* 116 * bfa_port_clear_stats_isr() 117 * 118 * 119 * @param[in] port - Pointer to the Port module 120 * status - Return status from the f/w 121 * 122 * @return void 123 */ 124 static void 125 bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status) 126 { 127 struct bfa_timeval_s tv; 128 129 port->stats_status = status; 130 port->stats_busy = BFA_FALSE; 131 132 /* 133 * re-initialize time stamp for stats reset 134 */ 135 bfa_os_gettimeofday(&tv); 136 port->stats_reset_time = tv.tv_sec; 137 138 if (port->stats_cbfn) { 139 port->stats_cbfn(port->stats_cbarg, status); 140 port->stats_cbfn = NULL; 141 } 142 } 143 144 /* 145 * bfa_port_isr() 146 * 147 * 148 * @param[in] Pointer to the Port module data structure. 149 * 150 * @return void 151 */ 152 static void 153 bfa_port_isr(void *cbarg, struct bfi_mbmsg_s *m) 154 { 155 struct bfa_port_s *port = (struct bfa_port_s *) cbarg; 156 union bfi_port_i2h_msg_u *i2hmsg; 157 158 i2hmsg = (union bfi_port_i2h_msg_u *) m; 159 bfa_trc(port, m->mh.msg_id); 160 161 switch (m->mh.msg_id) { 162 case BFI_PORT_I2H_ENABLE_RSP: 163 if (port->endis_pending == BFA_FALSE) 164 break; 165 bfa_port_enable_isr(port, i2hmsg->enable_rsp.status); 166 break; 167 168 case BFI_PORT_I2H_DISABLE_RSP: 169 if (port->endis_pending == BFA_FALSE) 170 break; 171 bfa_port_disable_isr(port, i2hmsg->disable_rsp.status); 172 break; 173 174 case BFI_PORT_I2H_GET_STATS_RSP: 175 /* Stats busy flag is still set? (may be cmd timed out) */ 176 if (port->stats_busy == BFA_FALSE) 177 break; 178 bfa_port_get_stats_isr(port, i2hmsg->getstats_rsp.status); 179 break; 180 181 case BFI_PORT_I2H_CLEAR_STATS_RSP: 182 if (port->stats_busy == BFA_FALSE) 183 break; 184 bfa_port_clear_stats_isr(port, i2hmsg->clearstats_rsp.status); 185 break; 186 187 default: 188 bfa_assert(0); 189 } 190 } 191 192 /* 193 * bfa_port_meminfo() 194 * 195 * 196 * @param[in] void 197 * 198 * @return Size of DMA region 199 */ 200 u32 201 bfa_port_meminfo(void) 202 { 203 return BFA_ROUNDUP(sizeof(union bfa_port_stats_u), BFA_DMA_ALIGN_SZ); 204 } 205 206 /* 207 * bfa_port_mem_claim() 208 * 209 * 210 * @param[in] port Port module pointer 211 * dma_kva Kernel Virtual Address of Port DMA Memory 212 * dma_pa Physical Address of Port DMA Memory 213 * 214 * @return void 215 */ 216 void 217 bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa) 218 { 219 port->stats_dma.kva = dma_kva; 220 port->stats_dma.pa = dma_pa; 221 } 222 223 /* 224 * bfa_port_enable() 225 * 226 * Send the Port enable request to the f/w 227 * 228 * @param[in] Pointer to the Port module data structure. 229 * 230 * @return Status 231 */ 232 bfa_status_t 233 bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, 234 void *cbarg) 235 { 236 struct bfi_port_generic_req_s *m; 237 238 if (bfa_ioc_is_disabled(port->ioc)) { 239 bfa_trc(port, BFA_STATUS_IOC_DISABLED); 240 return BFA_STATUS_IOC_DISABLED; 241 } 242 243 if (!bfa_ioc_is_operational(port->ioc)) { 244 bfa_trc(port, BFA_STATUS_IOC_FAILURE); 245 return BFA_STATUS_IOC_FAILURE; 246 } 247 248 if (port->endis_pending) { 249 bfa_trc(port, BFA_STATUS_DEVBUSY); 250 return BFA_STATUS_DEVBUSY; 251 } 252 253 m = (struct bfi_port_generic_req_s *) port->endis_mb.msg; 254 255 port->msgtag++; 256 port->endis_cbfn = cbfn; 257 port->endis_cbarg = cbarg; 258 port->endis_pending = BFA_TRUE; 259 260 bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_ENABLE_REQ, 261 bfa_ioc_portid(port->ioc)); 262 bfa_ioc_mbox_queue(port->ioc, &port->endis_mb); 263 264 return BFA_STATUS_OK; 265 } 266 267 /* 268 * bfa_port_disable() 269 * 270 * Send the Port disable request to the f/w 271 * 272 * @param[in] Pointer to the Port module data structure. 273 * 274 * @return Status 275 */ 276 bfa_status_t 277 bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, 278 void *cbarg) 279 { 280 struct bfi_port_generic_req_s *m; 281 282 if (bfa_ioc_is_disabled(port->ioc)) { 283 bfa_trc(port, BFA_STATUS_IOC_DISABLED); 284 return BFA_STATUS_IOC_DISABLED; 285 } 286 287 if (!bfa_ioc_is_operational(port->ioc)) { 288 bfa_trc(port, BFA_STATUS_IOC_FAILURE); 289 return BFA_STATUS_IOC_FAILURE; 290 } 291 292 if (port->endis_pending) { 293 bfa_trc(port, BFA_STATUS_DEVBUSY); 294 return BFA_STATUS_DEVBUSY; 295 } 296 297 m = (struct bfi_port_generic_req_s *) port->endis_mb.msg; 298 299 port->msgtag++; 300 port->endis_cbfn = cbfn; 301 port->endis_cbarg = cbarg; 302 port->endis_pending = BFA_TRUE; 303 304 bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_DISABLE_REQ, 305 bfa_ioc_portid(port->ioc)); 306 bfa_ioc_mbox_queue(port->ioc, &port->endis_mb); 307 308 return BFA_STATUS_OK; 309 } 310 311 /* 312 * bfa_port_get_stats() 313 * 314 * Send the request to the f/w to fetch Port statistics. 315 * 316 * @param[in] Pointer to the Port module data structure. 317 * 318 * @return Status 319 */ 320 bfa_status_t 321 bfa_port_get_stats(struct bfa_port_s *port, union bfa_port_stats_u *stats, 322 bfa_port_stats_cbfn_t cbfn, void *cbarg) 323 { 324 struct bfi_port_get_stats_req_s *m; 325 326 if (!bfa_ioc_is_operational(port->ioc)) { 327 bfa_trc(port, BFA_STATUS_IOC_FAILURE); 328 return BFA_STATUS_IOC_FAILURE; 329 } 330 331 if (port->stats_busy) { 332 bfa_trc(port, BFA_STATUS_DEVBUSY); 333 return BFA_STATUS_DEVBUSY; 334 } 335 336 m = (struct bfi_port_get_stats_req_s *) port->stats_mb.msg; 337 338 port->stats = stats; 339 port->stats_cbfn = cbfn; 340 port->stats_cbarg = cbarg; 341 port->stats_busy = BFA_TRUE; 342 bfa_dma_be_addr_set(m->dma_addr, port->stats_dma.pa); 343 344 bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_GET_STATS_REQ, 345 bfa_ioc_portid(port->ioc)); 346 bfa_ioc_mbox_queue(port->ioc, &port->stats_mb); 347 348 return BFA_STATUS_OK; 349 } 350 351 /* 352 * bfa_port_clear_stats() 353 * 354 * 355 * @param[in] Pointer to the Port module data structure. 356 * 357 * @return Status 358 */ 359 bfa_status_t 360 bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn, 361 void *cbarg) 362 { 363 struct bfi_port_generic_req_s *m; 364 365 if (!bfa_ioc_is_operational(port->ioc)) { 366 bfa_trc(port, BFA_STATUS_IOC_FAILURE); 367 return BFA_STATUS_IOC_FAILURE; 368 } 369 370 if (port->stats_busy) { 371 bfa_trc(port, BFA_STATUS_DEVBUSY); 372 return BFA_STATUS_DEVBUSY; 373 } 374 375 m = (struct bfi_port_generic_req_s *) port->stats_mb.msg; 376 377 port->stats_cbfn = cbfn; 378 port->stats_cbarg = cbarg; 379 port->stats_busy = BFA_TRUE; 380 381 bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_CLEAR_STATS_REQ, 382 bfa_ioc_portid(port->ioc)); 383 bfa_ioc_mbox_queue(port->ioc, &port->stats_mb); 384 385 return BFA_STATUS_OK; 386 } 387 388 /* 389 * bfa_port_hbfail() 390 * 391 * 392 * @param[in] Pointer to the Port module data structure. 393 * 394 * @return void 395 */ 396 void 397 bfa_port_hbfail(void *arg) 398 { 399 struct bfa_port_s *port = (struct bfa_port_s *) arg; 400 401 /* Fail any pending get_stats/clear_stats requests */ 402 if (port->stats_busy) { 403 if (port->stats_cbfn) 404 port->stats_cbfn(port->stats_cbarg, BFA_STATUS_FAILED); 405 port->stats_cbfn = NULL; 406 port->stats_busy = BFA_FALSE; 407 } 408 409 /* Clear any enable/disable is pending */ 410 if (port->endis_pending) { 411 if (port->endis_cbfn) 412 port->endis_cbfn(port->endis_cbarg, BFA_STATUS_FAILED); 413 port->endis_cbfn = NULL; 414 port->endis_pending = BFA_FALSE; 415 } 416 } 417 418 /* 419 * bfa_port_attach() 420 * 421 * 422 * @param[in] port - Pointer to the Port module data structure 423 * ioc - Pointer to the ioc module data structure 424 * dev - Pointer to the device driver module data structure 425 * The device driver specific mbox ISR functions have 426 * this pointer as one of the parameters. 427 * trcmod - 428 * 429 * @return void 430 */ 431 void 432 bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, 433 void *dev, struct bfa_trc_mod_s *trcmod) 434 { 435 struct bfa_timeval_s tv; 436 437 bfa_assert(port); 438 439 port->dev = dev; 440 port->ioc = ioc; 441 port->trcmod = trcmod; 442 443 port->stats_busy = BFA_FALSE; 444 port->endis_pending = BFA_FALSE; 445 port->stats_cbfn = NULL; 446 port->endis_cbfn = NULL; 447 448 bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port); 449 bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port); 450 bfa_ioc_hbfail_register(port->ioc, &port->hbfail); 451 452 /* 453 * initialize time stamp for stats reset 454 */ 455 bfa_os_gettimeofday(&tv); 456 port->stats_reset_time = tv.tv_sec; 457 458 bfa_trc(port, 0); 459 } 460 461 /* 462 * bfa_port_detach() 463 * 464 * 465 * @param[in] port - Pointer to the Port module data structure 466 * 467 * @return void 468 */ 469 void 470 bfa_port_detach(struct bfa_port_s *port) 471 { 472 bfa_trc(port, 0); 473 } 474