linux/drivers/scsi/bfa/bfa_port.c
<<
>>
Prefs
   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
  25BFA_TRC_FILE(CNA, PORT);
  26
  27#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
  28
  29static void
  30bfa_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 */
  59static void
  60bfa_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 */
  76static void
  77bfa_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 */
  93static void
  94bfa_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 */
 125static void
 126bfa_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 */
 153static void
 154bfa_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 */
 201u32
 202bfa_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 */
 217void
 218bfa_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 */
 233bfa_status_t
 234bfa_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 */
 277bfa_status_t
 278bfa_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 */
 321bfa_status_t
 322bfa_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 */
 360bfa_status_t
 361bfa_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 */
 397void
 398bfa_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 */
 432void
 433bfa_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