Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.26-rc5 213 lines 4.4 kB view raw
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);