linux/drivers/scsi/snic/snic_res.c
<<
>>
Prefs
   1/*
   2 * Copyright 2014 Cisco Systems, Inc.  All rights reserved.
   3 *
   4 * This program is free software; you may redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; version 2 of the License.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  11 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  12 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  13 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  14 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  15 * SOFTWARE.
  16 */
  17
  18#include <linux/errno.h>
  19#include <linux/types.h>
  20#include <linux/pci.h>
  21
  22#include "wq_enet_desc.h"
  23#include "cq_enet_desc.h"
  24#include "vnic_resource.h"
  25#include "vnic_dev.h"
  26#include "vnic_wq.h"
  27#include "vnic_cq.h"
  28#include "vnic_intr.h"
  29#include "vnic_stats.h"
  30#include "snic.h"
  31
  32int
  33snic_get_vnic_config(struct snic *snic)
  34{
  35        struct vnic_snic_config *c = &snic->config;
  36        int ret;
  37
  38#define GET_CONFIG(m) \
  39        do { \
  40                ret = svnic_dev_spec(snic->vdev, \
  41                                     offsetof(struct vnic_snic_config, m), \
  42                                     sizeof(c->m), \
  43                                     &c->m); \
  44                if (ret) { \
  45                        SNIC_HOST_ERR(snic->shost, \
  46                                      "Error getting %s, %d\n", #m, ret); \
  47                        return ret; \
  48                } \
  49        } while (0)
  50
  51        GET_CONFIG(wq_enet_desc_count);
  52        GET_CONFIG(maxdatafieldsize);
  53        GET_CONFIG(intr_timer);
  54        GET_CONFIG(intr_timer_type);
  55        GET_CONFIG(flags);
  56        GET_CONFIG(io_throttle_count);
  57        GET_CONFIG(port_down_timeout);
  58        GET_CONFIG(port_down_io_retries);
  59        GET_CONFIG(luns_per_tgt);
  60        GET_CONFIG(xpt_type);
  61        GET_CONFIG(hid);
  62
  63        c->wq_enet_desc_count = min_t(u32,
  64                                      VNIC_SNIC_WQ_DESCS_MAX,
  65                                      max_t(u32,
  66                                            VNIC_SNIC_WQ_DESCS_MIN,
  67                                            c->wq_enet_desc_count));
  68
  69        c->wq_enet_desc_count = ALIGN(c->wq_enet_desc_count, 16);
  70
  71        c->maxdatafieldsize = min_t(u32,
  72                                    VNIC_SNIC_MAXDATAFIELDSIZE_MAX,
  73                                    max_t(u32,
  74                                          VNIC_SNIC_MAXDATAFIELDSIZE_MIN,
  75                                          c->maxdatafieldsize));
  76
  77        c->io_throttle_count = min_t(u32,
  78                                     VNIC_SNIC_IO_THROTTLE_COUNT_MAX,
  79                                     max_t(u32,
  80                                           VNIC_SNIC_IO_THROTTLE_COUNT_MIN,
  81                                           c->io_throttle_count));
  82
  83        c->port_down_timeout = min_t(u32,
  84                                     VNIC_SNIC_PORT_DOWN_TIMEOUT_MAX,
  85                                     c->port_down_timeout);
  86
  87        c->port_down_io_retries = min_t(u32,
  88                                     VNIC_SNIC_PORT_DOWN_IO_RETRIES_MAX,
  89                                     c->port_down_io_retries);
  90
  91        c->luns_per_tgt = min_t(u32,
  92                                VNIC_SNIC_LUNS_PER_TARGET_MAX,
  93                                max_t(u32,
  94                                      VNIC_SNIC_LUNS_PER_TARGET_MIN,
  95                                      c->luns_per_tgt));
  96
  97        c->intr_timer = min_t(u32, VNIC_INTR_TIMER_MAX, c->intr_timer);
  98
  99        SNIC_INFO("vNIC resources wq %d\n", c->wq_enet_desc_count);
 100        SNIC_INFO("vNIC mtu %d intr timer %d\n",
 101                  c->maxdatafieldsize,
 102                  c->intr_timer);
 103
 104        SNIC_INFO("vNIC flags 0x%x luns per tgt %d\n",
 105                  c->flags,
 106                  c->luns_per_tgt);
 107
 108        SNIC_INFO("vNIC io throttle count %d\n", c->io_throttle_count);
 109        SNIC_INFO("vNIC port down timeout %d port down io retries %d\n",
 110                  c->port_down_timeout,
 111                  c->port_down_io_retries);
 112
 113        SNIC_INFO("vNIC back end type = %d\n", c->xpt_type);
 114        SNIC_INFO("vNIC hid = %d\n", c->hid);
 115
 116        return 0;
 117}
 118
 119void
 120snic_get_res_counts(struct snic *snic)
 121{
 122        snic->wq_count = svnic_dev_get_res_count(snic->vdev, RES_TYPE_WQ);
 123        SNIC_BUG_ON(snic->wq_count == 0);
 124        snic->cq_count = svnic_dev_get_res_count(snic->vdev, RES_TYPE_CQ);
 125        SNIC_BUG_ON(snic->cq_count == 0);
 126        snic->intr_count = svnic_dev_get_res_count(snic->vdev,
 127                                                  RES_TYPE_INTR_CTRL);
 128        SNIC_BUG_ON(snic->intr_count == 0);
 129}
 130
 131void
 132snic_free_vnic_res(struct snic *snic)
 133{
 134        unsigned int i;
 135
 136        for (i = 0; i < snic->wq_count; i++)
 137                svnic_wq_free(&snic->wq[i]);
 138
 139        for (i = 0; i < snic->cq_count; i++)
 140                svnic_cq_free(&snic->cq[i]);
 141
 142        for (i = 0; i < snic->intr_count; i++)
 143                svnic_intr_free(&snic->intr[i]);
 144}
 145
 146int
 147snic_alloc_vnic_res(struct snic *snic)
 148{
 149        enum vnic_dev_intr_mode intr_mode;
 150        unsigned int mask_on_assertion;
 151        unsigned int intr_offset;
 152        unsigned int err_intr_enable;
 153        unsigned int err_intr_offset;
 154        unsigned int i;
 155        int ret;
 156
 157        intr_mode = svnic_dev_get_intr_mode(snic->vdev);
 158
 159        SNIC_INFO("vNIC interrupt mode: %s\n",
 160                  ((intr_mode == VNIC_DEV_INTR_MODE_INTX) ?
 161                   "Legacy PCI INTx" :
 162                   ((intr_mode == VNIC_DEV_INTR_MODE_MSI) ?
 163                    "MSI" :
 164                    ((intr_mode == VNIC_DEV_INTR_MODE_MSIX) ?
 165                     "MSI-X" : "Unknown"))));
 166
 167        /* only MSI-X is supported */
 168        SNIC_BUG_ON(intr_mode != VNIC_DEV_INTR_MODE_MSIX);
 169
 170        SNIC_INFO("wq %d cq %d intr %d\n", snic->wq_count,
 171                  snic->cq_count,
 172                  snic->intr_count);
 173
 174
 175        /* Allocate WQs used for SCSI IOs */
 176        for (i = 0; i < snic->wq_count; i++) {
 177                ret = svnic_wq_alloc(snic->vdev,
 178                                     &snic->wq[i],
 179                                     i,
 180                                     snic->config.wq_enet_desc_count,
 181                                     sizeof(struct wq_enet_desc));
 182                if (ret)
 183                        goto error_cleanup;
 184        }
 185
 186        /* CQ for each WQ */
 187        for (i = 0; i < snic->wq_count; i++) {
 188                ret = svnic_cq_alloc(snic->vdev,
 189                                     &snic->cq[i],
 190                                     i,
 191                                     snic->config.wq_enet_desc_count,
 192                                     sizeof(struct cq_enet_wq_desc));
 193                if (ret)
 194                        goto error_cleanup;
 195        }
 196
 197        SNIC_BUG_ON(snic->cq_count != 2 * snic->wq_count);
 198        /* CQ for FW TO host */
 199        for (i = snic->wq_count; i < snic->cq_count; i++) {
 200                ret = svnic_cq_alloc(snic->vdev,
 201                                     &snic->cq[i],
 202                                     i,
 203                                     (snic->config.wq_enet_desc_count * 3),
 204                                     sizeof(struct snic_fw_req));
 205                if (ret)
 206                        goto error_cleanup;
 207        }
 208
 209        for (i = 0; i < snic->intr_count; i++) {
 210                ret = svnic_intr_alloc(snic->vdev, &snic->intr[i], i);
 211                if (ret)
 212                        goto error_cleanup;
 213        }
 214
 215        /*
 216         * Init WQ Resources.
 217         * WQ[0 to n] points to CQ[0 to n-1]
 218         * firmware to host comm points to CQ[n to m+1]
 219         */
 220        err_intr_enable = 1;
 221        err_intr_offset = snic->err_intr_offset;
 222
 223        for (i = 0; i < snic->wq_count; i++) {
 224                svnic_wq_init(&snic->wq[i],
 225                              i,
 226                              err_intr_enable,
 227                              err_intr_offset);
 228        }
 229
 230        for (i = 0; i < snic->cq_count; i++) {
 231                intr_offset = i;
 232
 233                svnic_cq_init(&snic->cq[i],
 234                              0 /* flow_control_enable */,
 235                              1 /* color_enable */,
 236                              0 /* cq_head */,
 237                              0 /* cq_tail */,
 238                              1 /* cq_tail_color */,
 239                              1 /* interrupt_enable */,
 240                              1 /* cq_entry_enable */,
 241                              0 /* cq_message_enable */,
 242                              intr_offset,
 243                              0 /* cq_message_addr */);
 244        }
 245
 246        /*
 247         * Init INTR resources
 248         * Assumption : snic is always in MSI-X mode
 249         */
 250        SNIC_BUG_ON(intr_mode != VNIC_DEV_INTR_MODE_MSIX);
 251        mask_on_assertion = 1;
 252
 253        for (i = 0; i < snic->intr_count; i++) {
 254                svnic_intr_init(&snic->intr[i],
 255                                snic->config.intr_timer,
 256                                snic->config.intr_timer_type,
 257                                mask_on_assertion);
 258        }
 259
 260        /* init the stats memory by making the first call here */
 261        ret = svnic_dev_stats_dump(snic->vdev, &snic->stats);
 262        if (ret) {
 263                SNIC_HOST_ERR(snic->shost,
 264                              "svnic_dev_stats_dump failed - x%x\n",
 265                              ret);
 266                goto error_cleanup;
 267        }
 268
 269        /* Clear LIF stats */
 270        svnic_dev_stats_clear(snic->vdev);
 271        ret = 0;
 272
 273        return ret;
 274
 275error_cleanup:
 276        snic_free_vnic_res(snic);
 277
 278        return ret;
 279}
 280
 281void
 282snic_log_q_error(struct snic *snic)
 283{
 284        unsigned int i;
 285        u32 err_status;
 286
 287        for (i = 0; i < snic->wq_count; i++) {
 288                err_status = ioread32(&snic->wq[i].ctrl->error_status);
 289                if (err_status)
 290                        SNIC_HOST_ERR(snic->shost,
 291                                      "WQ[%d] error status %d\n",
 292                                      i,
 293                                      err_status);
 294        }
 295} /* end of snic_log_q_error */
 296