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