linux/drivers/md/dm-hw-handler.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
   3 *
   4 * This file is released under the GPL.
   5 *
   6 * Multipath hardware handler registration.
   7 */
   8
   9#include "dm.h"
  10#include "dm-hw-handler.h"
  11
  12#include <linux/slab.h>
  13
  14struct hwh_internal {
  15        struct hw_handler_type hwht;
  16
  17        struct list_head list;
  18        long use;
  19};
  20
  21#define hwht_to_hwhi(__hwht) container_of((__hwht), struct hwh_internal, hwht)
  22
  23static LIST_HEAD(_hw_handlers);
  24static DECLARE_RWSEM(_hwh_lock);
  25
  26static struct hwh_internal *__find_hw_handler_type(const char *name)
  27{
  28        struct hwh_internal *hwhi;
  29
  30        list_for_each_entry(hwhi, &_hw_handlers, list) {
  31                if (!strcmp(name, hwhi->hwht.name))
  32                        return hwhi;
  33        }
  34
  35        return NULL;
  36}
  37
  38static struct hwh_internal *get_hw_handler(const char *name)
  39{
  40        struct hwh_internal *hwhi;
  41
  42        down_read(&_hwh_lock);
  43        hwhi = __find_hw_handler_type(name);
  44        if (hwhi) {
  45                if ((hwhi->use == 0) && !try_module_get(hwhi->hwht.module))
  46                        hwhi = NULL;
  47                else
  48                        hwhi->use++;
  49        }
  50        up_read(&_hwh_lock);
  51
  52        return hwhi;
  53}
  54
  55struct hw_handler_type *dm_get_hw_handler(const char *name)
  56{
  57        struct hwh_internal *hwhi;
  58
  59        if (!name)
  60                return NULL;
  61
  62        hwhi = get_hw_handler(name);
  63        if (!hwhi) {
  64                request_module("dm-%s", name);
  65                hwhi = get_hw_handler(name);
  66        }
  67
  68        return hwhi ? &hwhi->hwht : NULL;
  69}
  70
  71void dm_put_hw_handler(struct hw_handler_type *hwht)
  72{
  73        struct hwh_internal *hwhi;
  74
  75        if (!hwht)
  76                return;
  77
  78        down_read(&_hwh_lock);
  79        hwhi = __find_hw_handler_type(hwht->name);
  80        if (!hwhi)
  81                goto out;
  82
  83        if (--hwhi->use == 0)
  84                module_put(hwhi->hwht.module);
  85
  86        BUG_ON(hwhi->use < 0);
  87
  88      out:
  89        up_read(&_hwh_lock);
  90}
  91
  92static struct hwh_internal *_alloc_hw_handler(struct hw_handler_type *hwht)
  93{
  94        struct hwh_internal *hwhi = kzalloc(sizeof(*hwhi), GFP_KERNEL);
  95
  96        if (hwhi)
  97                hwhi->hwht = *hwht;
  98
  99        return hwhi;
 100}
 101
 102int dm_register_hw_handler(struct hw_handler_type *hwht)
 103{
 104        int r = 0;
 105        struct hwh_internal *hwhi = _alloc_hw_handler(hwht);
 106
 107        if (!hwhi)
 108                return -ENOMEM;
 109
 110        down_write(&_hwh_lock);
 111
 112        if (__find_hw_handler_type(hwht->name)) {
 113                kfree(hwhi);
 114                r = -EEXIST;
 115        } else
 116                list_add(&hwhi->list, &_hw_handlers);
 117
 118        up_write(&_hwh_lock);
 119
 120        return r;
 121}
 122
 123int dm_unregister_hw_handler(struct hw_handler_type *hwht)
 124{
 125        struct hwh_internal *hwhi;
 126
 127        down_write(&_hwh_lock);
 128
 129        hwhi = __find_hw_handler_type(hwht->name);
 130        if (!hwhi) {
 131                up_write(&_hwh_lock);
 132                return -EINVAL;
 133        }
 134
 135        if (hwhi->use) {
 136                up_write(&_hwh_lock);
 137                return -ETXTBSY;
 138        }
 139
 140        list_del(&hwhi->list);
 141
 142        up_write(&_hwh_lock);
 143
 144        kfree(hwhi);
 145
 146        return 0;
 147}
 148
 149unsigned dm_scsi_err_handler(struct hw_handler *hwh, struct bio *bio)
 150{
 151#if 0
 152        int sense_key, asc, ascq;
 153
 154        if (bio->bi_error & BIO_SENSE) {
 155                /* FIXME: This is just an initial guess. */
 156                /* key / asc / ascq */
 157                sense_key = (bio->bi_error >> 16) & 0xff;
 158                asc = (bio->bi_error >> 8) & 0xff;
 159                ascq = bio->bi_error & 0xff;
 160
 161                switch (sense_key) {
 162                        /* This block as a whole comes from the device.
 163                         * So no point retrying on another path. */
 164                case 0x03:      /* Medium error */
 165                case 0x05:      /* Illegal request */
 166                case 0x07:      /* Data protect */
 167                case 0x08:      /* Blank check */
 168                case 0x0a:      /* copy aborted */
 169                case 0x0c:      /* obsolete - no clue ;-) */
 170                case 0x0d:      /* volume overflow */
 171                case 0x0e:      /* data miscompare */
 172                case 0x0f:      /* reserved - no idea either. */
 173                        return MP_ERROR_IO;
 174
 175                        /* For these errors it's unclear whether they
 176                         * come from the device or the controller.
 177                         * So just lets try a different path, and if
 178                         * it eventually succeeds, user-space will clear
 179                         * the paths again... */
 180                case 0x02:      /* Not ready */
 181                case 0x04:      /* Hardware error */
 182                case 0x09:      /* vendor specific */
 183                case 0x0b:      /* Aborted command */
 184                        return MP_FAIL_PATH;
 185
 186                case 0x06:      /* Unit attention - might want to decode */
 187                        if (asc == 0x04 && ascq == 0x01)
 188                                /* "Unit in the process of
 189                                 * becoming ready" */
 190                                return 0;
 191                        return MP_FAIL_PATH;
 192
 193                        /* FIXME: For Unit Not Ready we may want
 194                         * to have a generic pg activation
 195                         * feature (START_UNIT). */
 196
 197                        /* Should these two ever end up in the
 198                         * error path? I don't think so. */
 199                case 0x00:      /* No sense */
 200                case 0x01:      /* Recovered error */
 201                        return 0;
 202                }
 203        }
 204#endif
 205
 206        /* We got no idea how to decode the other kinds of errors ->
 207         * assume generic error condition. */
 208        return MP_FAIL_PATH;
 209}
 210
 211EXPORT_SYMBOL_GPL(dm_register_hw_handler);
 212EXPORT_SYMBOL_GPL(dm_unregister_hw_handler);
 213EXPORT_SYMBOL_GPL(dm_scsi_err_handler);
 214