[PATCH] pcmcia: cleanup cs.c, reduce size
[linux-2.6] / drivers / md / dm-hw-handler.c
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
14 struct 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
23 static LIST_HEAD(_hw_handlers);
24 static DECLARE_RWSEM(_hwh_lock);
25
26 static 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
38 static 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
55 struct 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
71 void 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
93 static 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
105 int 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
126 int 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
152 unsigned 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
214 EXPORT_SYMBOL_GPL(dm_register_hw_handler);
215 EXPORT_SYMBOL_GPL(dm_unregister_hw_handler);
216 EXPORT_SYMBOL_GPL(dm_scsi_err_handler);