[PATCH] ACPI based I/O APIC hot-plug: add interfaces
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / md / dm-hw-handler.c
blob4cc0010e01569a16f0fd3bc53c2f3a365bff3e07
1 /*
2 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
4 * This file is released under the GPL.
6 * Multipath hardware handler registration.
7 */
9 #include "dm.h"
10 #include "dm-hw-handler.h"
12 #include <linux/slab.h>
14 struct hwh_internal {
15 struct hw_handler_type hwht;
17 struct list_head list;
18 long use;
21 #define hwht_to_hwhi(__hwht) container_of((__hwht), struct hwh_internal, hwht)
23 static LIST_HEAD(_hw_handlers);
24 static DECLARE_RWSEM(_hwh_lock);
26 static struct hwh_internal *__find_hw_handler_type(const char *name)
28 struct hwh_internal *hwhi;
30 list_for_each_entry(hwhi, &_hw_handlers, list) {
31 if (!strcmp(name, hwhi->hwht.name))
32 return hwhi;
35 return NULL;
38 static struct hwh_internal *get_hw_handler(const char *name)
40 struct hwh_internal *hwhi;
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++;
50 up_read(&_hwh_lock);
52 return hwhi;
55 struct hw_handler_type *dm_get_hw_handler(const char *name)
57 struct hwh_internal *hwhi;
59 if (!name)
60 return NULL;
62 hwhi = get_hw_handler(name);
63 if (!hwhi) {
64 request_module("dm-%s", name);
65 hwhi = get_hw_handler(name);
68 return hwhi ? &hwhi->hwht : NULL;
71 void dm_put_hw_handler(struct hw_handler_type *hwht)
73 struct hwh_internal *hwhi;
75 if (!hwht)
76 return;
78 down_read(&_hwh_lock);
79 hwhi = __find_hw_handler_type(hwht->name);
80 if (!hwhi)
81 goto out;
83 if (--hwhi->use == 0)
84 module_put(hwhi->hwht.module);
86 if (hwhi->use < 0)
87 BUG();
89 out:
90 up_read(&_hwh_lock);
93 static struct hwh_internal *_alloc_hw_handler(struct hw_handler_type *hwht)
95 struct hwh_internal *hwhi = kmalloc(sizeof(*hwhi), GFP_KERNEL);
97 if (hwhi) {
98 memset(hwhi, 0, sizeof(*hwhi));
99 hwhi->hwht = *hwht;
102 return hwhi;
105 int dm_register_hw_handler(struct hw_handler_type *hwht)
107 int r = 0;
108 struct hwh_internal *hwhi = _alloc_hw_handler(hwht);
110 if (!hwhi)
111 return -ENOMEM;
113 down_write(&_hwh_lock);
115 if (__find_hw_handler_type(hwht->name)) {
116 kfree(hwhi);
117 r = -EEXIST;
118 } else
119 list_add(&hwhi->list, &_hw_handlers);
121 up_write(&_hwh_lock);
123 return r;
126 int dm_unregister_hw_handler(struct hw_handler_type *hwht)
128 struct hwh_internal *hwhi;
130 down_write(&_hwh_lock);
132 hwhi = __find_hw_handler_type(hwht->name);
133 if (!hwhi) {
134 up_write(&_hwh_lock);
135 return -EINVAL;
138 if (hwhi->use) {
139 up_write(&_hwh_lock);
140 return -ETXTBSY;
143 list_del(&hwhi->list);
145 up_write(&_hwh_lock);
147 kfree(hwhi);
149 return 0;
152 unsigned dm_scsi_err_handler(struct hw_handler *hwh, struct bio *bio)
154 #if 0
155 int sense_key, asc, ascq;
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;
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;
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;
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;
196 /* FIXME: For Unit Not Ready we may want
197 * to have a generic pg activation
198 * feature (START_UNIT). */
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;
207 #endif
209 /* We got no idea how to decode the other kinds of errors ->
210 * assume generic error condition. */
211 return MP_FAIL_PATH;
214 EXPORT_SYMBOL_GPL(dm_register_hw_handler);
215 EXPORT_SYMBOL_GPL(dm_unregister_hw_handler);
216 EXPORT_SYMBOL_GPL(dm_scsi_err_handler);