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.21-rc6 215 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 = kmalloc(sizeof(*hwhi), GFP_KERNEL); 95 96 if (hwhi) { 97 memset(hwhi, 0, sizeof(*hwhi)); 98 hwhi->hwht = *hwht; 99 } 100 101 return hwhi; 102} 103 104int dm_register_hw_handler(struct hw_handler_type *hwht) 105{ 106 int r = 0; 107 struct hwh_internal *hwhi = _alloc_hw_handler(hwht); 108 109 if (!hwhi) 110 return -ENOMEM; 111 112 down_write(&_hwh_lock); 113 114 if (__find_hw_handler_type(hwht->name)) { 115 kfree(hwhi); 116 r = -EEXIST; 117 } else 118 list_add(&hwhi->list, &_hw_handlers); 119 120 up_write(&_hwh_lock); 121 122 return r; 123} 124 125int dm_unregister_hw_handler(struct hw_handler_type *hwht) 126{ 127 struct hwh_internal *hwhi; 128 129 down_write(&_hwh_lock); 130 131 hwhi = __find_hw_handler_type(hwht->name); 132 if (!hwhi) { 133 up_write(&_hwh_lock); 134 return -EINVAL; 135 } 136 137 if (hwhi->use) { 138 up_write(&_hwh_lock); 139 return -ETXTBSY; 140 } 141 142 list_del(&hwhi->list); 143 144 up_write(&_hwh_lock); 145 146 kfree(hwhi); 147 148 return 0; 149} 150 151unsigned dm_scsi_err_handler(struct hw_handler *hwh, struct bio *bio) 152{ 153#if 0 154 int sense_key, asc, ascq; 155 156 if (bio->bi_error & BIO_SENSE) { 157 /* FIXME: This is just an initial guess. */ 158 /* key / asc / ascq */ 159 sense_key = (bio->bi_error >> 16) & 0xff; 160 asc = (bio->bi_error >> 8) & 0xff; 161 ascq = bio->bi_error & 0xff; 162 163 switch (sense_key) { 164 /* This block as a whole comes from the device. 165 * So no point retrying on another path. */ 166 case 0x03: /* Medium error */ 167 case 0x05: /* Illegal request */ 168 case 0x07: /* Data protect */ 169 case 0x08: /* Blank check */ 170 case 0x0a: /* copy aborted */ 171 case 0x0c: /* obsolete - no clue ;-) */ 172 case 0x0d: /* volume overflow */ 173 case 0x0e: /* data miscompare */ 174 case 0x0f: /* reserved - no idea either. */ 175 return MP_ERROR_IO; 176 177 /* For these errors it's unclear whether they 178 * come from the device or the controller. 179 * So just lets try a different path, and if 180 * it eventually succeeds, user-space will clear 181 * the paths again... */ 182 case 0x02: /* Not ready */ 183 case 0x04: /* Hardware error */ 184 case 0x09: /* vendor specific */ 185 case 0x0b: /* Aborted command */ 186 return MP_FAIL_PATH; 187 188 case 0x06: /* Unit attention - might want to decode */ 189 if (asc == 0x04 && ascq == 0x01) 190 /* "Unit in the process of 191 * becoming ready" */ 192 return 0; 193 return MP_FAIL_PATH; 194 195 /* FIXME: For Unit Not Ready we may want 196 * to have a generic pg activation 197 * feature (START_UNIT). */ 198 199 /* Should these two ever end up in the 200 * error path? I don't think so. */ 201 case 0x00: /* No sense */ 202 case 0x01: /* Recovered error */ 203 return 0; 204 } 205 } 206#endif 207 208 /* We got no idea how to decode the other kinds of errors -> 209 * assume generic error condition. */ 210 return MP_FAIL_PATH; 211} 212 213EXPORT_SYMBOL_GPL(dm_register_hw_handler); 214EXPORT_SYMBOL_GPL(dm_unregister_hw_handler); 215EXPORT_SYMBOL_GPL(dm_scsi_err_handler);