linux/drivers/block/rsxx/config.c
<<
>>
Prefs
   1/*
   2* Filename: config.c
   3*
   4*
   5* Authors: Joshua Morris <josh.h.morris@us.ibm.com>
   6*       Philip Kelleher <pjk1939@linux.vnet.ibm.com>
   7*
   8* (C) Copyright 2013 IBM Corporation
   9*
  10* This program is free software; you can redistribute it and/or
  11* modify it under the terms of the GNU General Public License as
  12* published by the Free Software Foundation; either version 2 of the
  13* License, or (at your option) any later version.
  14*
  15* This program is distributed in the hope that it will be useful, but
  16* WITHOUT ANY WARRANTY; without even the implied warranty of
  17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18* General Public License for more details.
  19*
  20* You should have received a copy of the GNU General Public License
  21* along with this program; if not, write to the Free Software Foundation,
  22* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23*/
  24
  25#include <linux/types.h>
  26#include <linux/crc32.h>
  27#include <linux/swab.h>
  28
  29#include "rsxx_priv.h"
  30#include "rsxx_cfg.h"
  31
  32static void initialize_config(struct rsxx_card_cfg *cfg)
  33{
  34        cfg->hdr.version = RSXX_CFG_VERSION;
  35
  36        cfg->data.block_size        = RSXX_HW_BLK_SIZE;
  37        cfg->data.stripe_size       = RSXX_HW_BLK_SIZE;
  38        cfg->data.vendor_id         = RSXX_VENDOR_ID_IBM;
  39        cfg->data.cache_order       = (-1);
  40        cfg->data.intr_coal.mode    = RSXX_INTR_COAL_DISABLED;
  41        cfg->data.intr_coal.count   = 0;
  42        cfg->data.intr_coal.latency = 0;
  43}
  44
  45static u32 config_data_crc32(struct rsxx_card_cfg *cfg)
  46{
  47        /*
  48         * Return the compliment of the CRC to ensure compatibility
  49         * (i.e. this is how early rsxx drivers did it.)
  50         */
  51
  52        return ~crc32(~0, &cfg->data, sizeof(cfg->data));
  53}
  54
  55
  56/*----------------- Config Byte Swap Functions -------------------*/
  57static void config_hdr_be_to_cpu(struct card_cfg_hdr *hdr)
  58{
  59        hdr->version = be32_to_cpu((__force __be32) hdr->version);
  60        hdr->crc     = be32_to_cpu((__force __be32) hdr->crc);
  61}
  62
  63static void config_hdr_cpu_to_be(struct card_cfg_hdr *hdr)
  64{
  65        hdr->version = (__force u32) cpu_to_be32(hdr->version);
  66        hdr->crc     = (__force u32) cpu_to_be32(hdr->crc);
  67}
  68
  69static void config_data_swab(struct rsxx_card_cfg *cfg)
  70{
  71        u32 *data = (u32 *) &cfg->data;
  72        int i;
  73
  74        for (i = 0; i < (sizeof(cfg->data) / 4); i++)
  75                data[i] = swab32(data[i]);
  76}
  77
  78static void config_data_le_to_cpu(struct rsxx_card_cfg *cfg)
  79{
  80        u32 *data = (u32 *) &cfg->data;
  81        int i;
  82
  83        for (i = 0; i < (sizeof(cfg->data) / 4); i++)
  84                data[i] = le32_to_cpu((__force __le32) data[i]);
  85}
  86
  87static void config_data_cpu_to_le(struct rsxx_card_cfg *cfg)
  88{
  89        u32 *data = (u32 *) &cfg->data;
  90        int i;
  91
  92        for (i = 0; i < (sizeof(cfg->data) / 4); i++)
  93                data[i] = (__force u32) cpu_to_le32(data[i]);
  94}
  95
  96
  97/*----------------- Config Operations ------------------*/
  98static int rsxx_save_config(struct rsxx_cardinfo *card)
  99{
 100        struct rsxx_card_cfg cfg;
 101        int st;
 102
 103        memcpy(&cfg, &card->config, sizeof(cfg));
 104
 105        if (unlikely(cfg.hdr.version != RSXX_CFG_VERSION)) {
 106                dev_err(CARD_TO_DEV(card),
 107                        "Cannot save config with invalid version %d\n",
 108                        cfg.hdr.version);
 109                return -EINVAL;
 110        }
 111
 112        /* Convert data to little endian for the CRC calculation. */
 113        config_data_cpu_to_le(&cfg);
 114
 115        cfg.hdr.crc = config_data_crc32(&cfg);
 116
 117        /*
 118         * Swap the data from little endian to big endian so it can be
 119         * stored.
 120         */
 121        config_data_swab(&cfg);
 122        config_hdr_cpu_to_be(&cfg.hdr);
 123
 124        st = rsxx_creg_write(card, CREG_ADD_CONFIG, sizeof(cfg), &cfg, 1);
 125        if (st)
 126                return st;
 127
 128        return 0;
 129}
 130
 131int rsxx_load_config(struct rsxx_cardinfo *card)
 132{
 133        int st;
 134        u32 crc;
 135
 136        st = rsxx_creg_read(card, CREG_ADD_CONFIG, sizeof(card->config),
 137                                &card->config, 1);
 138        if (st) {
 139                dev_err(CARD_TO_DEV(card),
 140                        "Failed reading card config.\n");
 141                return st;
 142        }
 143
 144        config_hdr_be_to_cpu(&card->config.hdr);
 145
 146        if (card->config.hdr.version == RSXX_CFG_VERSION) {
 147                /*
 148                 * We calculate the CRC with the data in little endian, because
 149                 * early drivers did not take big endian CPUs into account.
 150                 * The data is always stored in big endian, so we need to byte
 151                 * swap it before calculating the CRC.
 152                 */
 153
 154                config_data_swab(&card->config);
 155
 156                /* Check the CRC */
 157                crc = config_data_crc32(&card->config);
 158                if (crc != card->config.hdr.crc) {
 159                        dev_err(CARD_TO_DEV(card),
 160                                "Config corruption detected!\n");
 161                        dev_info(CARD_TO_DEV(card),
 162                                "CRC (sb x%08x is x%08x)\n",
 163                                card->config.hdr.crc, crc);
 164                        return -EIO;
 165                }
 166
 167                /* Convert the data to CPU byteorder */
 168                config_data_le_to_cpu(&card->config);
 169
 170        } else if (card->config.hdr.version != 0) {
 171                dev_err(CARD_TO_DEV(card),
 172                        "Invalid config version %d.\n",
 173                        card->config.hdr.version);
 174                /*
 175                 * Config version changes require special handling from the
 176                 * user
 177                 */
 178                return -EINVAL;
 179        } else {
 180                dev_info(CARD_TO_DEV(card),
 181                        "Initializing card configuration.\n");
 182                initialize_config(&card->config);
 183                st = rsxx_save_config(card);
 184                if (st)
 185                        return st;
 186        }
 187
 188        card->config_valid = 1;
 189
 190        dev_dbg(CARD_TO_DEV(card), "version:     x%08x\n",
 191                card->config.hdr.version);
 192        dev_dbg(CARD_TO_DEV(card), "crc:         x%08x\n",
 193                card->config.hdr.crc);
 194        dev_dbg(CARD_TO_DEV(card), "block_size:  x%08x\n",
 195                card->config.data.block_size);
 196        dev_dbg(CARD_TO_DEV(card), "stripe_size: x%08x\n",
 197                card->config.data.stripe_size);
 198        dev_dbg(CARD_TO_DEV(card), "vendor_id:   x%08x\n",
 199                card->config.data.vendor_id);
 200        dev_dbg(CARD_TO_DEV(card), "cache_order: x%08x\n",
 201                card->config.data.cache_order);
 202        dev_dbg(CARD_TO_DEV(card), "mode:        x%08x\n",
 203                card->config.data.intr_coal.mode);
 204        dev_dbg(CARD_TO_DEV(card), "count:       x%08x\n",
 205                card->config.data.intr_coal.count);
 206        dev_dbg(CARD_TO_DEV(card), "latency:     x%08x\n",
 207                 card->config.data.intr_coal.latency);
 208
 209        return 0;
 210}
 211
 212