blob: baafaaba4d4b5632d177f1a3e1f8cb374de1119c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
Alasdair G Kergon5e198d92005-05-05 16:16:09 -070026static struct hwh_internal *__find_hw_handler_type(const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -070027{
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
Eric Sesterhenn4401d132006-03-24 18:36:27 +010086 BUG_ON(hwhi->use < 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
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);