1 | /* $NetBSD: ata_raid.c,v 1.39 2016/09/27 08:05:34 pgoyette Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2003 Wasabi Systems, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. |
8 | * |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions |
11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. All advertising materials mentioning features or use of this software |
18 | * must display the following acknowledgement: |
19 | * This product includes software developed for the NetBSD Project by |
20 | * Wasabi Systems, Inc. |
21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
22 | * or promote products derived from this software without specific prior |
23 | * written permission. |
24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
35 | * POSSIBILITY OF SUCH DAMAGE. |
36 | */ |
37 | |
38 | /* |
39 | * Support for autoconfiguration of RAID sets on ATA RAID controllers. |
40 | */ |
41 | |
42 | #include <sys/cdefs.h> |
43 | __KERNEL_RCSID(0, "$NetBSD: ata_raid.c,v 1.39 2016/09/27 08:05:34 pgoyette Exp $" ); |
44 | |
45 | #include <sys/param.h> |
46 | #include <sys/buf.h> |
47 | #include <sys/bufq.h> |
48 | #include <sys/conf.h> |
49 | #include <sys/device.h> |
50 | #include <sys/disk.h> |
51 | #include <sys/disklabel.h> |
52 | #include <sys/fcntl.h> |
53 | #include <sys/malloc.h> |
54 | #include <sys/vnode.h> |
55 | #include <sys/proc.h> |
56 | #include <sys/module.h> |
57 | |
58 | #include <miscfs/specfs/specdev.h> |
59 | |
60 | #include <dev/ata/atareg.h> |
61 | #include <dev/ata/atavar.h> |
62 | #include <dev/ata/wdvar.h> |
63 | |
64 | #include <dev/ata/ata_raidreg.h> |
65 | #include <dev/ata/ata_raidvar.h> |
66 | |
67 | #include "locators.h" |
68 | #include "ioconf.h" |
69 | |
70 | #ifdef ATA_RAID_DEBUG |
71 | #define DPRINTF(x) printf x |
72 | #else |
73 | #define DPRINTF(x) /* nothing */ |
74 | #endif |
75 | |
76 | static int ataraid_match(device_t, cfdata_t, void *); |
77 | static void ataraid_attach(device_t, device_t, void *); |
78 | static int ataraid_rescan(device_t, const char *, const int *); |
79 | static int ataraid_print(void *, const char *); |
80 | |
81 | static int ata_raid_finalize(device_t); |
82 | |
83 | static int finalize_done; |
84 | |
85 | ataraid_array_info_list_t ataraid_array_info_list = |
86 | TAILQ_HEAD_INITIALIZER(ataraid_array_info_list); |
87 | u_int ataraid_array_info_count; |
88 | |
89 | CFATTACH_DECL3_NEW(ataraid, 0, |
90 | ataraid_match, ataraid_attach, NULL, NULL, ataraid_rescan, NULL, 0); |
91 | |
92 | /* |
93 | * ataraidattach: |
94 | * |
95 | * Pseudo-device attach routine. |
96 | */ |
97 | void |
98 | ataraidattach(int count) |
99 | { |
100 | |
101 | /* |
102 | * Register a finalizer which will be used to actually configure |
103 | * the logical disks configured by ataraid. |
104 | */ |
105 | finalize_done = 0; |
106 | if (config_finalize_register(NULL, ata_raid_finalize) != 0) |
107 | aprint_normal("WARNING: " |
108 | "unable to register ATA RAID finalizer\n" ); |
109 | } |
110 | |
111 | /* |
112 | * Use the config_finalizer to rescan for new devices, since the |
113 | * ld_ataraid driver might not be immediately available. |
114 | */ |
115 | |
116 | /* ARGSUSED */ |
117 | static int |
118 | ataraid_rescan(device_t self, const char *attr, const int *flags) |
119 | { |
120 | |
121 | finalize_done = 0; |
122 | (void)ata_raid_finalize(self); |
123 | |
124 | return 0; |
125 | } |
126 | |
127 | /* |
128 | * ata_raid_type_name: |
129 | * |
130 | * Return the type of ATA RAID. |
131 | */ |
132 | const char * |
133 | ata_raid_type_name(u_int type) |
134 | { |
135 | static const char *ata_raid_type_names[] = { |
136 | "Promise" , |
137 | "Adaptec" , |
138 | "VIA V-RAID" , |
139 | "nVidia" , |
140 | "JMicron" , |
141 | "Intel MatrixRAID" |
142 | }; |
143 | |
144 | if (type < __arraycount(ata_raid_type_names)) |
145 | return (ata_raid_type_names[type]); |
146 | |
147 | return (NULL); |
148 | } |
149 | |
150 | /* |
151 | * ata_raid_finalize: |
152 | * |
153 | * Autoconfiguration finalizer for ATA RAID. |
154 | */ |
155 | static int |
156 | ata_raid_finalize(device_t self) |
157 | { |
158 | static struct cfdata ataraid_cfdata = { |
159 | .cf_name = "ataraid" , |
160 | .cf_atname = "ataraid" , |
161 | .cf_unit = 0, |
162 | .cf_fstate = FSTATE_STAR, |
163 | }; |
164 | |
165 | /* |
166 | * Only run once for each instantiation |
167 | */ |
168 | if (finalize_done) |
169 | return 0; |
170 | finalize_done = 1; |
171 | |
172 | if (TAILQ_EMPTY(&ataraid_array_info_list)) |
173 | goto out; |
174 | |
175 | if (config_attach_pseudo(&ataraid_cfdata) == NULL) |
176 | printf("%s: unable to attach an instance\n" , |
177 | ataraid_cd.cd_name); |
178 | |
179 | out: |
180 | return (1); |
181 | } |
182 | |
183 | /* |
184 | * ataraid_match: |
185 | * |
186 | * Autoconfiguration glue: match routine. |
187 | */ |
188 | static int |
189 | ataraid_match(device_t parent, cfdata_t cf, void *aux) |
190 | { |
191 | |
192 | /* pseudo-device; always present */ |
193 | return (1); |
194 | } |
195 | |
196 | /* |
197 | * ataraid_attach: |
198 | * |
199 | * Autoconfiguration glue: attach routine. We attach the children. |
200 | */ |
201 | static void |
202 | ataraid_attach(device_t parent, device_t self, void *aux) |
203 | { |
204 | struct ataraid_array_info *aai; |
205 | int locs[ATARAIDCF_NLOCS]; |
206 | |
207 | /* |
208 | * We're a pseudo-device, so we get to announce our own |
209 | * presence. |
210 | */ |
211 | aprint_normal_dev(self, "found %u RAID volume%s\n" , |
212 | ataraid_array_info_count, |
213 | ataraid_array_info_count == 1 ? "" : "s" ); |
214 | |
215 | TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { |
216 | locs[ATARAIDCF_VENDTYPE] = aai->aai_type; |
217 | locs[ATARAIDCF_UNIT] = aai->aai_arrayno; |
218 | |
219 | config_found_sm_loc(self, "ataraid" , locs, aai, |
220 | ataraid_print, config_stdsubmatch); |
221 | } |
222 | } |
223 | |
224 | /* |
225 | * ataraid_print: |
226 | * |
227 | * Autoconfiguration glue: print routine. |
228 | */ |
229 | static int |
230 | ataraid_print(void *aux, const char *pnp) |
231 | { |
232 | struct ataraid_array_info *aai = aux; |
233 | |
234 | if (pnp != NULL) |
235 | aprint_normal("block device at %s" , pnp); |
236 | aprint_normal(" vendtype %d unit %d" , aai->aai_type, aai->aai_arrayno); |
237 | return (UNCONF); |
238 | } |
239 | |
240 | /* |
241 | * ata_raid_check_component: |
242 | * |
243 | * Check the component for a RAID configuration structure. |
244 | * Called via autoconfiguration callback. |
245 | */ |
246 | void |
247 | ata_raid_check_component(device_t self) |
248 | { |
249 | struct wd_softc *sc = device_private(self); |
250 | |
251 | if (ata_raid_read_config_adaptec(sc) == 0) |
252 | return; |
253 | if (ata_raid_read_config_promise(sc) == 0) |
254 | return; |
255 | if (ata_raid_read_config_via(sc) == 0) |
256 | return; |
257 | if (ata_raid_read_config_nvidia(sc) == 0) |
258 | return; |
259 | if (ata_raid_read_config_jmicron(sc) == 0) |
260 | return; |
261 | if (ata_raid_read_config_intel(sc) == 0) |
262 | return; |
263 | } |
264 | |
265 | struct ataraid_array_info * |
266 | ata_raid_get_array_info(u_int type, u_int arrayno) |
267 | { |
268 | struct ataraid_array_info *aai, *laai; |
269 | |
270 | TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { |
271 | if (aai->aai_type == type && |
272 | aai->aai_arrayno == arrayno) |
273 | goto out; |
274 | } |
275 | |
276 | /* Need to allocate a new one. */ |
277 | aai = malloc(sizeof(*aai), M_DEVBUF, M_WAITOK | M_ZERO); |
278 | aai->aai_type = type; |
279 | aai->aai_arrayno = arrayno; |
280 | aai->aai_curdisk = 0; |
281 | |
282 | ataraid_array_info_count++; |
283 | |
284 | /* Sort it into the list: type first, then array number. */ |
285 | TAILQ_FOREACH(laai, &ataraid_array_info_list, aai_list) { |
286 | if (aai->aai_type < laai->aai_type) { |
287 | TAILQ_INSERT_BEFORE(laai, aai, aai_list); |
288 | goto out; |
289 | } |
290 | if (aai->aai_type == laai->aai_type && |
291 | aai->aai_arrayno < laai->aai_arrayno) { |
292 | TAILQ_INSERT_BEFORE(laai, aai, aai_list); |
293 | goto out; |
294 | } |
295 | } |
296 | TAILQ_INSERT_TAIL(&ataraid_array_info_list, aai, aai_list); |
297 | |
298 | out: |
299 | return (aai); |
300 | } |
301 | |
302 | int |
303 | ata_raid_config_block_rw(struct vnode *vp, daddr_t blkno, void *tbuf, |
304 | size_t size, int bflags) |
305 | { |
306 | struct buf *bp; |
307 | int error; |
308 | |
309 | bp = getiobuf(vp, false); |
310 | bp->b_blkno = blkno; |
311 | bp->b_bcount = bp->b_resid = size; |
312 | bp->b_flags = bflags; |
313 | bp->b_proc = curproc; |
314 | bp->b_data = tbuf; |
315 | SET(bp->b_cflags, BC_BUSY); /* mark buffer busy */ |
316 | |
317 | VOP_STRATEGY(vp, bp); |
318 | error = biowait(bp); |
319 | |
320 | putiobuf(bp); |
321 | return (error); |
322 | } |
323 | |
324 | MODULE(MODULE_CLASS_DRIVER, ataraid, "" ); |
325 | |
326 | #ifdef _MODULE |
327 | CFDRIVER_DECL(ataraid, DV_DISK, NULL); |
328 | #endif |
329 | |
330 | static int |
331 | ataraid_modcmd(modcmd_t cmd, void *arg) |
332 | { |
333 | int error = 0; |
334 | |
335 | switch (cmd) { |
336 | case MODULE_CMD_INIT: |
337 | #ifdef _MODULE |
338 | error = config_cfdriver_attach(&ataraid_cd); |
339 | if (error) |
340 | break; |
341 | |
342 | error = config_cfattach_attach(ataraid_cd.cd_name, &ataraid_ca); |
343 | if (error) { |
344 | config_cfdriver_detach(&ataraid_cd); |
345 | aprint_error("%s: unable to register cfattach for \n" |
346 | "%s, error %d" , __func__, ataraid_cd.cd_name, |
347 | error); |
348 | break; |
349 | } |
350 | #endif |
351 | break; |
352 | case MODULE_CMD_FINI: |
353 | #ifdef _MODULE |
354 | |
355 | error = config_cfattach_detach(ataraid_cd.cd_name, &ataraid_ca); |
356 | if (error) { |
357 | aprint_error("%s: failed to detach %s cfattach, " |
358 | "error %d\n" , __func__, ataraid_cd.cd_name, error); |
359 | break; |
360 | } |
361 | error = config_cfdriver_detach(&ataraid_cd); |
362 | if (error) { |
363 | (void)config_cfattach_attach(ataraid_cd.cd_name, |
364 | &ataraid_ca); |
365 | aprint_error("%s: failed to detach %s cfdriver, " |
366 | "error %d\n" , __func__, ataraid_cd.cd_name, error); |
367 | break; |
368 | } |
369 | #endif |
370 | break; |
371 | case MODULE_CMD_STAT: |
372 | default: |
373 | error = ENOTTY; |
374 | } |
375 | |
376 | return error; |
377 | } |
378 | |