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