1
2
3
4
5
6
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
156
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
163
164 case 0x03:
165 case 0x05:
166 case 0x07:
167 case 0x08:
168 case 0x0a:
169 case 0x0c:
170 case 0x0d:
171 case 0x0e:
172 case 0x0f:
173 return MP_ERROR_IO;
174
175
176
177
178
179
180 case 0x02:
181 case 0x04:
182 case 0x09:
183 case 0x0b:
184 return MP_FAIL_PATH;
185
186 case 0x06:
187 if (asc == 0x04 && ascq == 0x01)
188
189
190 return 0;
191 return MP_FAIL_PATH;
192
193
194
195
196
197
198
199 case 0x00:
200 case 0x01:
201 return 0;
202 }
203 }
204#endif
205
206
207
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);
214