xref: /netbsd-src/sys/dev/ata/ata_raid.c (revision de1dfb1250df962f1ff3a011772cf58e605aed11)
1 /*	$NetBSD: ata_raid.c,v 1.9 2004/09/13 12:55:47 drochner 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.9 2004/09/13 12:55:47 drochner Exp $");
44 
45 #include <sys/param.h>
46 #include <sys/buf.h>
47 #include <sys/conf.h>
48 #include <sys/device.h>
49 #include <sys/disk.h>
50 #include <sys/disklabel.h>
51 #include <sys/fcntl.h>
52 #include <sys/malloc.h>
53 #include <sys/vnode.h>
54 
55 #include <miscfs/specfs/specdev.h>
56 
57 #include <dev/ata/atareg.h>
58 #include <dev/ata/atavar.h>
59 #include <dev/ata/wdvar.h>
60 
61 #include <dev/ata/ata_raidreg.h>
62 #include <dev/ata/ata_raidvar.h>
63 
64 #include "locators.h"
65 
66 #ifdef ATA_RAID_DEBUG
67 #define	DPRINTF(x)	printf x
68 #else
69 #define	DPRINTF(x)	/* nothing */
70 #endif
71 
72 void		ataraidattach(int);
73 
74 static int	ataraid_match(struct device *, struct cfdata *, void *);
75 static void	ataraid_attach(struct device *, struct device *, void *);
76 static int	ataraid_print(void *, const char *);
77 
78 static int	ataraid_submatch(struct device *, struct cfdata *,
79 				 const locdesc_t *, void *);
80 
81 static int	ata_raid_finalize(struct device *);
82 
83 ataraid_array_info_list_t ataraid_array_info_list =
84     TAILQ_HEAD_INITIALIZER(ataraid_array_info_list);
85 u_int ataraid_array_info_count;
86 
87 CFATTACH_DECL(ataraid, sizeof(struct device),
88     ataraid_match, ataraid_attach, NULL, NULL);
89 
90 /*
91  * ataraidattach:
92  *
93  *	Pseudo-device attach routine.
94  */
95 void
96 ataraidattach(int count)
97 {
98 
99 	/*
100 	 * Register a finalizer which will be used to actually configure
101 	 * the logical disks configured by ataraid.
102 	 */
103 	if (config_finalize_register(NULL, ata_raid_finalize) != 0)
104 		printf("WARNING: unable to register ATA RAID finalizer\n");
105 }
106 
107 /*
108  * ata_raid_type_name:
109  *
110  *	Return the type of ATA RAID.
111  */
112 const char *
113 ata_raid_type_name(u_int type)
114 {
115 	static const char *ata_raid_type_names[] = {
116 		"Promise",
117 	};
118 
119 	if (type <= ATA_RAID_TYPE_MAX)
120 		return (ata_raid_type_names[type]);
121 
122 	return (NULL);
123 }
124 
125 /*
126  * ata_raid_finalize:
127  *
128  *	Autoconfiguration finalizer for ATA RAID.
129  */
130 static int
131 ata_raid_finalize(struct device *self)
132 {
133 	extern struct cfdriver ataraid_cd;
134 	static int done_once;
135 	int error;
136 
137 	/*
138 	 * Since we only handle real hardware, we only need to be
139 	 * called once.
140 	 */
141 	if (done_once)
142 		return (0);
143 	done_once = 1;
144 
145 	if (TAILQ_EMPTY(&ataraid_array_info_list))
146 		goto out;
147 
148 	error = config_cfattach_attach(ataraid_cd.cd_name, &ataraid_ca);
149 	if (error) {
150 		printf("%s: unable to register cfattach, error = %d\n",
151 		    ataraid_cd.cd_name, error);
152 		(void) config_cfdriver_detach(&ataraid_cd);
153 		goto out;
154 	}
155 
156 	if (config_attach_pseudo(ataraid_cd.cd_name, -1) == NULL)
157 		printf("%s: unable to attach an instance\n",
158 		    ataraid_cd.cd_name);
159 
160  out:
161 	return (1);
162 }
163 
164 /*
165  * ataraid_match:
166  *
167  *	Autoconfiguration glue: match routine.
168  */
169 static int
170 ataraid_match(struct device *parent, struct cfdata *cf, void *aux)
171 {
172 
173 	/* pseudo-device; always present */
174 	return (1);
175 }
176 
177 /*
178  * ataraid_attach:
179  *
180  *	Autoconfiguration glue: attach routine.  We attach the children.
181  */
182 static void
183 ataraid_attach(struct device *parent, struct device *self, void *aux)
184 {
185 	struct ataraid_array_info *aai;
186 	int help[3];
187 	locdesc_t *ldesc = (void *)help; /* XXX */
188 
189 	/*
190 	 * We're a pseudo-device, so we get to announce our own
191 	 * presence.
192 	 */
193 	aprint_normal("%s: found %u RAID volume%s\n",
194 	    self->dv_xname, ataraid_array_info_count,
195 	    ataraid_array_info_count == 1 ? "" : "s");
196 
197 	TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) {
198 		ldesc->len = 2;
199 		ldesc->locs[ATARAIDCF_VENDTYPE] = aai->aai_type;
200 		ldesc->locs[ATARAIDCF_UNIT] = aai->aai_arrayno;
201 
202 		config_found_sm_loc(self, "ataraid", NULL, aai,
203 				    ataraid_print, ataraid_submatch);
204 	}
205 }
206 
207 /*
208  * ataraid_print:
209  *
210  *	Autoconfiguration glue: print routine.
211  */
212 static int
213 ataraid_print(void *aux, const char *pnp)
214 {
215 	struct ataraid_array_info *aai = aux;
216 
217 	if (pnp != NULL)
218 		aprint_normal("block device at %s", pnp);
219 	aprint_normal(" vendtype %d unit %d", aai->aai_type, aai->aai_arrayno);
220 	return (UNCONF);
221 }
222 
223 /*
224  * ataraid_submatch:
225  *
226  *	Submatch routine for ATA RAID logical disks.
227  */
228 static int
229 ataraid_submatch(struct device *parent, struct cfdata *cf,
230 		 const locdesc_t *ldesc, void *aux)
231 {
232 
233 	if (cf->cf_loc[ATARAIDCF_VENDTYPE] != ATARAIDCF_VENDTYPE_DEFAULT &&
234 	    cf->cf_loc[ATARAIDCF_VENDTYPE] != ldesc->locs[ATARAIDCF_VENDTYPE])
235 		return (0);
236 
237 	if (cf->cf_loc[ATARAIDCF_UNIT] != ATARAIDCF_UNIT_DEFAULT &&
238 	    cf->cf_loc[ATARAIDCF_UNIT] != ldesc->locs[ATARAIDCF_UNIT])
239 		return (0);
240 
241 	return (config_match(parent, cf, aux));
242 }
243 
244 /*
245  * ata_raid_check_component:
246  *
247  *	Check the component for a RAID configuration structure.
248  *	Called via autoconfiguration callback.
249  */
250 void
251 ata_raid_check_component(struct device *self)
252 {
253 	struct wd_softc *sc = (void *) self;
254 
255 	if (ata_raid_read_config_promise(sc) == 0)
256 		return;
257 }
258 
259 struct ataraid_array_info *
260 ata_raid_get_array_info(u_int type, u_int arrayno)
261 {
262 	struct ataraid_array_info *aai, *laai;
263 
264 	TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) {
265 		if (aai->aai_type == type &&
266 		    aai->aai_arrayno == arrayno)
267 			goto out;
268 	}
269 
270 	/* Need to allocate a new one. */
271 	aai = malloc(sizeof(*aai), M_DEVBUF, M_WAITOK | M_ZERO);
272 	aai->aai_type = type;
273 	aai->aai_arrayno = arrayno;
274 
275 	ataraid_array_info_count++;
276 
277 	if (TAILQ_EMPTY(&ataraid_array_info_list)) {
278 		TAILQ_INSERT_TAIL(&ataraid_array_info_list, aai, aai_list);
279 		goto out;
280 	}
281 
282 	/* Sort it into the list: type first, then array number. */
283 	TAILQ_FOREACH(laai, &ataraid_array_info_list, aai_list) {
284 		if (aai->aai_type < laai->aai_type) {
285 			TAILQ_INSERT_BEFORE(laai, aai, aai_list);
286 			goto out;
287 		}
288 		if (aai->aai_type == laai->aai_type &&
289 		    aai->aai_arrayno < laai->aai_arrayno) {
290 			TAILQ_INSERT_BEFORE(laai, aai, aai_list);
291 			goto out;
292 		}
293 	}
294 	TAILQ_INSERT_TAIL(&ataraid_array_info_list, aai, aai_list);
295 
296  out:
297 	return (aai);
298 }
299 
300 int
301 ata_raid_config_block_rw(struct vnode *vp, daddr_t blkno, void *buf,
302     size_t size, int bflags)
303 {
304 	struct buf *bp;
305 	int error, s;
306 
307 	s = splbio();
308 	bp = pool_get(&bufpool, PR_WAITOK);
309 	splx(s);
310 	BUF_INIT(bp);
311 
312 	bp->b_vp = vp;
313 	bp->b_blkno = blkno;
314 	bp->b_bcount = bp->b_resid = size;
315 	bp->b_flags = bflags;
316 	bp->b_proc = curproc;
317 	bp->b_data = buf;
318 
319 	VOP_STRATEGY(vp, bp);
320 	error = biowait(bp);
321 
322 	s = splbio();
323 	pool_put(&bufpool, bp);
324 	splx(s);
325 	return (error);
326 }
327