Logo Search packages:      
Sourcecode: dmraid version File versions

jm.c

/*
 * JMicron metadata format handler.
 *
 * Copyright (C) 2006  Heinz Mauelshagen, Red Hat GmbH.
 *                     All rights reserved.
 *
 * See file LICENSE at the top of this source tree for license information.
 */

#define     HANDLER "jmicron"

#include "internal.h"
#define     FORMAT_HANDLER
#include "jm.h"

#if   BYTE_ORDER != LITTLE_ENDIAN
#  define   DM_BYTEORDER_SWAB
#  include  <datastruct/byteorder.h>
#endif

static const char *handler = HANDLER;

/* RAID set name */
static int member(struct jm *jm);
static char *name(struct lib_context *lc, struct raid_dev *rd,
              unsigned int subset)
{
      size_t len;
      struct jm *jm = META(rd, jm);
      char buf[2], *ret, *name = (char *) jm->name;

      /* Name always 0 terminated ? */
      if ((len = strlen(name)) > JM_NAME_LEN)
            len = JM_NAME_LEN;

      len += sizeof(HANDLER) + 2;
      if (jm->mode == JM_T_RAID01)
            len++;

      if ((ret = dbg_malloc(len))) {
            if (jm->mode == JM_T_RAID01 && subset)
                  sprintf(buf, "-%u", member(jm) / 2);
            else
                  *buf = 0;

            sprintf(ret, "%s_%s%s", HANDLER, name, buf);
      }

      return ret;
}

/*
 * Retrieve status of device.
 * FIXME: is this sufficient to cover all state ?
 */
static enum status status(struct jm *jm)
{
      return jm->attribute & ~(JM_MOUNT|JM_BOOTABLE|JM_BADSEC|JM_ACTIVE|JM_UNSYNC|JM_NEWEST) ? s_broken : s_ok;
}

/* Neutralize disk type */
static enum type type(struct jm *jm)
{
      /* Mapping of JM types to generic types */
      static struct types types[] = {
            { JM_T_JBOD, t_linear},
            { JM_T_RAID0, t_raid0},
            { JM_T_RAID01, t_raid1},
            { JM_T_RAID1, t_raid1},
            { 0, t_undef},
      };

      return rd_type(types, (unsigned int) jm->mode);
}

/* Calculate checksum on metadata */
static int checksum(struct jm *jm)
{
      int count = 64;
      uint16_t *p = (uint16_t*) jm, sum = 0;

        while (count--)
            sum += *p++;

      /* FIXME: shouldn't this be one value only ? */
      return sum == 0 || sum == 1;
}

static inline unsigned int segment(uint32_t m)
{
      return (unsigned int) (m & JM_SEG_MASK);
}

static inline unsigned int disk(unsigned int m)
{
      return (unsigned int) (m & JM_HDD_MASK);
}

static int member(struct jm *jm)
{
      unsigned int i = JM_MEMBERS;

      while (i--) {
            if (disk(jm->member[i]) == disk(jm->identity))
                  return i;
      }

      return -1;
}

/* Decide about ordering sequence of RAID device. */
static int dev_sort(struct list_head *pos, struct list_head *new)
{
      return member(META(RD(new), jm)) < member(META(RD(pos), jm));
}

/* Decide about ordering sequence of RAID subset. */
static int set_sort(struct list_head *pos, struct list_head *new)
{
      return member(META(RD_RS(RS(pos)), jm)) > 1;
}

static unsigned int stride(unsigned int shift)
{
      return 1 << (shift + 1);
}

static void super_created(struct raid_set *super, void *private)
{
      super->type   = t_raid0;
      super->stride = stride(META((private), jm)->block);
}

/*
 * Group the RAID disk into a JM set.
 *
 * Check device hierarchy and create super set appropriately.
 */
static int group_rd(struct lib_context *lc, struct raid_set *rs,
                struct raid_set **ss, struct raid_dev *rd)
{
      struct jm *jm = META(rd, jm);

      if (!init_raid_set(lc, rs, rd, stride(jm->block), jm->mode, handler))
            return 0;

      list_add_sorted(lc, &rs->devs, &rd->devs, dev_sort);

      switch (jm->mode) {
      case JM_T_JBOD:
      case JM_T_RAID0:
      case JM_T_RAID1:
            if (!find_set(lc, NULL, rs->name, FIND_TOP))
                  list_add_tail(&rs->list, LC_RS(lc));

            break;

      case JM_T_RAID01:
            if (!(*ss = join_superset(lc, name, super_created,
                                set_sort, rs, rd)))
                  return 0;
      }

      return 1;
}

/*
 * Add a JMicron RAID device to a set.
 */
static struct raid_set *jm_group(struct lib_context *lc,
                               struct raid_dev *rd)
{
      struct raid_set *rs, *ss = NULL;

      if (T_SPARE(rd))
            return NULL;

      if ((rs = find_or_alloc_raid_set(lc, rd->name, FIND_ALL, rd,
                               NO_LIST, NO_CREATE, NO_CREATE_ARG)))
            return group_rd(lc, rs, &ss, rd) ? (ss ? ss : rs) : NULL;

      return NULL;
}

/*
 * Read a JMicron RAID device.
 */
/* Endianess conversion. */
#if   BYTE_ORDER == LITTLE_ENDIAN
#  define   to_cpu      NULL
#else
static void to_cpu(void *meta)
{
      unsigned int i;
      struct jm *jm = meta;

      CVT16(jm->version);
      CVT16(jm->checksum);
      CVT32(jm->identity);

      CVT32(jm->segment.base);
      CVT32(jm->segment.range);
      CVT16(jm->segment.range2);

      CVT16(jm->attribute);

      for (i = 0; i < JM_SPARES; i++)
            CVT32(jm->spare[i]);

      for (i = 0; i < JM_MEMBERS; i++)
            CVT32(jm->member[i]);
}
#endif

/* Magic check. */
static int is_jm(struct lib_context *lc, struct dev_info *di, void *meta)
{
      struct jm *jm = meta;

      return !strncmp((const char*) jm->signature,
                  JM_SIGNATURE, JM_SIGNATURE_LEN)
             && checksum(jm);
}

static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
                struct dev_info *di, void *meta, union read_info *info);
static struct raid_dev *jm_read(struct lib_context *lc,
                              struct dev_info *di)
{
      return read_raid_dev(lc, di, NULL,
                       sizeof(struct jm), JM_CONFIGOFFSET,
                       to_cpu, is_jm, NULL, setup_rd, handler);
}

/*
 * Write a JMicron RAID device.
 */
static int jm_write(struct lib_context *lc,
                  struct raid_dev *rd, int erase)
{
      int ret;
#if   BYTE_ORDER != LITTLE_ENDIAN
      struct jm *jm = META(rd, jm);

      to_disk(jm);
#endif
      ret = write_metadata(lc, handler, rd, -1, erase);
#if   BYTE_ORDER != LITTLE_ENDIAN
      to_cpu(jm);
#endif
      return ret;
}

/*
 * Check a JMicron RAID set.
 *
 * FIXME: more sanity checks.
 */
static unsigned int devices(struct raid_dev *rd, void *context)
{
      unsigned int r = JM_MEMBERS;
      struct jm *jm = META(rd, jm);

      while (r-- && !jm->member[r]);

      return ++r;
}

static int jm_check(struct lib_context *lc, struct raid_set *rs)
{
      return check_raid_set(lc, rs, devices, NULL,
                        NO_CHECK_RD, NULL, handler);
}

/*
 * IO error event handler.
 */
static int event_io(struct lib_context *lc, struct event_io *e_io)
{
      struct raid_dev *rd = e_io->rd;
      struct jm *jm = META(rd, jm);

      /* Avoid write trashing. */
      if (S_BROKEN(status(jm)))
            return 0;

      jm->checksum = 1; /* FIXME: how to flag a JMicron disk bad? */

      return 1;
}

static struct event_handlers jm_event_handlers = {
      .io = event_io,
      .rd = NULL, /* FIXME: no device add/remove event handler yet. */
};

#ifdef DMRAID_NATIVE_LOG
/*
 * Log native information about an JM RAID device.
 */
static void jm_log(struct lib_context *lc, struct raid_dev *rd)
{
      unsigned int i;
      struct jm *jm = META(rd, jm);

      log_print(lc, "%s (%s):", rd->di->path, handler);
      P("signature: %c%c", jm, jm->signature,
        jm->signature[0], jm->signature[1]);
      P("version: %u%u", jm, jm->version,
        JM_MAJOR_VERSION(jm), JM_MINOR_VERSION(jm));
      DP("checksum: %u", jm, jm->checksum);
      DP("identity: 0x%x", jm, jm->identity);
      DP("base: %u", jm, jm->segment.base);
      DP("range: %u", jm, jm->segment.range);
      DP("range2: %u", jm, jm->segment.range2);
      DP("name: \"%s\"", jm, jm->name);
      DP("name: %u", jm, jm->mode);
      DP("block: %u", jm, jm->block);
      DP("attribute: %u", jm, jm->attribute);
      for (i = 0; i < JM_SPARES; i++)
            P2("spare[%d]: 0x%x", jm, i, jm->spare[i]);
      for (i = 0; i < JM_MEMBERS; i++)
            P2("member[%d]: 0x%x", jm, i, jm->member[i]);
}
#endif

static struct dmraid_format jm_format = {
      .name = HANDLER,
      .descr      = "JMicron ATARAID",
      .caps = "S,0,1",
      .format = FMT_RAID,
      .read = jm_read,
      .write      = jm_write,
      .group      = jm_group,
      .check      = jm_check,
      .events     = &jm_event_handlers,
#ifdef DMRAID_NATIVE_LOG
      .log  = jm_log,
#endif
};

/* Register this format handler with the format core. */
int register_jm(struct lib_context *lc)
{
      return register_format_handler(lc, &jm_format);
}

/* Calculate RAID device size in sectors depending on RAID type. */
static inline uint64_t sectors(struct jm *jm)
{
      /* range * 32MB[sectors] + range2 */
      return jm->segment.range * 32*2048 + jm->segment.range2;
}

/* Set the RAID device contents up derived from the JMicron ones */
static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
                struct dev_info *di, void *meta, union read_info *info)
{
      struct jm *jm = meta;

      if (!(rd->meta_areas = alloc_meta_areas(lc, rd, handler, 1)))
            return 0;

      rd->meta_areas->offset = JM_CONFIGOFFSET >> 9;
      rd->meta_areas->size = sizeof(*jm);
      rd->meta_areas->area = (void*) jm;

      rd->di = di;
      rd->fmt = &jm_format;

      rd->status = status(jm);
      rd->type   = type(jm);

      rd->offset = jm->segment.base;
      if (!(rd->sectors = sectors(jm)))
            return log_zero_sectors(lc, di->path, handler);

      return (rd->name = name(lc, rd, 1)) ? 1 : 0;
}

Generated by  Doxygen 1.6.0   Back to index