xref: /netbsd/sys/arch/arm/arm/disksubr.c (revision 6550d01e)
1 /*	$NetBSD: disksubr.c,v 1.23 2009/03/15 22:23:16 cegger Exp $	*/
2 
3 /*
4  * Copyright (c) 1998 Christopher G. Demetriou.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Christopher G. Demetriou
17  *	for the NetBSD Project.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
35  * All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  * 3. Neither the name of the University nor the names of its contributors
46  *    may be used to endorse or promote products derived from this software
47  *    without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  *
61  *	from: @(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
62  */
63 
64 /*
65  * Copyright (c) 1995 Mark Brinicombe
66  * All rights reserved.
67  *
68  * Redistribution and use in source and binary forms, with or without
69  * modification, are permitted provided that the following conditions
70  * are met:
71  * 1. Redistributions of source code must retain the above copyright
72  *    notice, this list of conditions and the following disclaimer.
73  * 2. Redistributions in binary form must reproduce the above copyright
74  *    notice, this list of conditions and the following disclaimer in the
75  *    documentation and/or other materials provided with the distribution.
76  * 3. All advertising materials mentioning features or use of this software
77  *    must display the following acknowledgement:
78  *	This product includes software developed by the University of
79  *	California, Berkeley and its contributors.
80  * 4. Neither the name of the University nor the names of its contributors
81  *    may be used to endorse or promote products derived from this software
82  *    without specific prior written permission.
83  *
84  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
85  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
86  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
87  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
88  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
89  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
90  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
91  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
92  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
93  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
94  * SUCH DAMAGE.
95  *
96  *	from: @(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
97  */
98 
99 #include <sys/cdefs.h>
100 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.23 2009/03/15 22:23:16 cegger Exp $");
101 
102 #include <sys/param.h>
103 #include <sys/systm.h>
104 #include <sys/buf.h>
105 #include <sys/dkbad.h>
106 #include <sys/disklabel.h>
107 #include <sys/syslog.h>
108 #include <sys/device.h>
109 #include <sys/disk.h>
110 
111 /*
112  * Attempt to read a disk label from a device
113  * using the indicated strategy routine.
114  * The label must be partly set up before this:
115  * secpercyl, secsize and anything required for a block i/o read
116  * operation in the driver's strategy/start routines
117  * must be filled in before calling us.
118  *
119  * If dos partition table requested, attempt to load it and
120  * find disklabel inside a DOS partition. Also, if bad block
121  * table needed, attempt to extract it as well. Return buffer
122  * for use in signalling errors if requested.
123  *
124  * Returns null on success and an error string on failure.
125  */
126 
127 const char *
128 readdisklabel(dev_t dev, void (*strat)(struct buf *),
129 		struct disklabel *lp, struct cpu_disklabel *osdep)
130 {
131 	struct buf *bp;
132 	struct disklabel *dlp;
133 	const char *msg = NULL;
134 	int cyl, netbsdpartoff, i, found = 0;
135 
136 	/* minimal requirements for archtypal disk label */
137 
138 	if (lp->d_secsize == 0)
139 		lp->d_secsize = DEV_BSIZE;
140 
141 	if (lp->d_secperunit == 0)
142 		lp->d_secperunit = 0x1fffffff;
143 
144 	if (lp->d_npartitions < RAW_PART + 1)
145 	      lp->d_npartitions = RAW_PART + 1;
146 
147 	if (lp->d_partitions[RAW_PART].p_size == 0) {
148 		lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
149 		lp->d_partitions[RAW_PART].p_offset = 0;
150 		lp->d_partitions[RAW_PART].p_size = 0x1fffffff;
151 	}
152 
153 	/* obtain buffer to probe drive with */
154 
155 	bp = geteblk((int)lp->d_secsize);
156 
157 	/* request no partition relocation by driver on I/O operations */
158 
159 	bp->b_dev = dev;
160 
161 	/* do netbsd partitions in the process of getting disklabel? */
162 
163 	netbsdpartoff = 0;
164 	cyl = LABELSECTOR / lp->d_secpercyl;
165 
166 	if (osdep) {
167 		if (filecore_label_read(dev, strat,lp, osdep, &msg, &cyl,
168 		      &netbsdpartoff) ||
169 		    mbr_label_read(dev, strat, lp, osdep, &msg, &cyl,
170 		      &netbsdpartoff)) {
171 			if (msg != NULL)
172 				goto done;
173 		} else {
174 			/*
175 			 * We didn't find anything we like; NetBSD native.
176 			 * netbsdpartoff and cyl should be unchanged.
177 			 */
178 			KASSERT(netbsdpartoff == 0);
179 			KASSERT(cyl == (LABELSECTOR / lp->d_secpercyl));
180 		}
181 	}
182 
183 	/* next, dig out disk label */
184 
185 	bp->b_blkno = netbsdpartoff + LABELSECTOR;
186 	bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
187 	bp->b_bcount = lp->d_secsize;
188 	bp->b_flags |= B_READ;
189 	(*strat)(bp);
190 
191 	/* if successful, locate disk label within block and validate */
192 
193 	if (biowait(bp)) {
194 		msg = "disk label I/O error";
195 		goto done;
196 	}
197 	for (dlp = (struct disklabel *)bp->b_data;
198 	    dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize - sizeof(*dlp));
199 	    dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
200 		if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
201 			continue;
202 		} else if (dlp->d_npartitions > MAXPARTITIONS ||
203 			   dkcksum(dlp) != 0)
204 			msg = "disk label corrupted";
205 		else {
206 			*lp = *dlp;
207 			msg = NULL;
208 			found = 1;
209 			break;
210 		}
211 	}
212 
213 	if (msg != NULL || found == 0)
214 		goto done;
215 
216 	/* obtain bad sector table if requested and present */
217 	if (osdep && (lp->d_flags & D_BADSECT)) {
218 		struct dkbad *bdp = &osdep->bad;
219 		struct dkbad *db;
220 
221 		i = 0;
222 		do {
223 			/* read a bad sector table */
224 			bp->b_oflags &= ~(BO_DONE);
225 			bp->b_flags |= B_READ;
226 			bp->b_blkno = lp->d_secperunit - lp->d_nsectors + i;
227 			if (lp->d_secsize > DEV_BSIZE)
228 				bp->b_blkno *= lp->d_secsize / DEV_BSIZE;
229 			else
230 				bp->b_blkno /= DEV_BSIZE / lp->d_secsize;
231 			bp->b_bcount = lp->d_secsize;
232 			bp->b_cylinder = lp->d_ncylinders - 1;
233 			(*strat)(bp);
234 
235 			/* if successful, validate, otherwise try another */
236 			if (biowait(bp)) {
237 				msg = "bad sector table I/O error";
238 			} else {
239 				db = (struct dkbad *)(bp->b_data);
240 #define DKBAD_MAGIC 0x4321
241 				if (db->bt_mbz == 0
242 					&& db->bt_flag == DKBAD_MAGIC) {
243 					msg = NULL;
244 					*bdp = *db;
245 					break;
246 				} else
247 					msg = "bad sector table corrupted";
248 			}
249 		} while (bp->b_error != 0 && (i += 2) < 10 &&
250 			i < lp->d_nsectors);
251 	}
252 
253 done:
254 	brelse(bp, 0);
255 	return (msg);
256 }
257 
258 
259 /*
260  * Check new disk label for sensibility
261  * before setting it.
262  */
263 
264 int
265 setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask, struct cpu_disklabel *osdep)
266 {
267 	int i;
268 	struct partition *opp, *npp;
269 
270 	/* sanity clause */
271 
272 	if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0
273 	    || (nlp->d_secsize % DEV_BSIZE) != 0)
274 		return(EINVAL);
275 
276 	/* special case to allow disklabel to be invalidated */
277 
278 	if (nlp->d_magic == 0xffffffff) {
279 		*olp = *nlp;
280 		return (0);
281 	}
282 
283 	if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC
284 	    || dkcksum(nlp) != 0)
285 		return (EINVAL);
286 
287 	/* XXX missing check if other acorn/dos partitions will be overwritten */
288 
289 	while (openmask != 0) {
290 		i = ffs(openmask) - 1;
291 		openmask &= ~(1 << i);
292 		if (nlp->d_npartitions <= i)
293 			return (EBUSY);
294 		opp = &olp->d_partitions[i];
295 		npp = &nlp->d_partitions[i];
296 		if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
297 			return (EBUSY);
298 		/*
299 		 * Copy internally-set partition information
300 		 * if new label doesn't include it.		XXX
301 		 */
302 		if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
303 			npp->p_fstype = opp->p_fstype;
304 			npp->p_fsize = opp->p_fsize;
305 			npp->p_frag = opp->p_frag;
306 			npp->p_cpg = opp->p_cpg;
307 		}
308 	}
309 
310 	nlp->d_checksum = 0;
311 	nlp->d_checksum = dkcksum(nlp);
312 	*olp = *nlp;
313 	return (0);
314 }
315 
316 
317 /*
318  * Write disk label back to device after modification.
319  */
320 
321 int
322 writedisklabel(dev_t dev, void (*strat)(struct buf *),
323 	struct disklabel *lp, struct cpu_disklabel *osdep)
324 {
325 	struct buf *bp;
326 	struct disklabel *dlp;
327 	int cyl, netbsdpartoff;
328 	int error = 0, rv;
329 
330 	/* get a buffer and initialize it */
331 
332 	bp = geteblk((int)lp->d_secsize);
333 	bp->b_dev = dev;
334 
335 	/* do netbsd partitions in the process of getting disklabel? */
336 
337 	netbsdpartoff = 0;
338 	cyl = LABELSECTOR / lp->d_secpercyl;
339 
340 	if (osdep) {
341 		if ((rv = filecore_label_locate(dev, strat,lp, osdep, &cyl,
342 		      &netbsdpartoff)) != 0||
343 		    (rv = mbr_label_locate(dev, strat, lp, osdep, &cyl,
344 		      &netbsdpartoff)) != 0) {
345 			if (rv < 0) {
346 			    error = -rv;
347 			    goto done;
348 			}
349 		} else {
350 			/*
351 			 * We didn't find anything we like; NetBSD native.
352 			 * netbsdpartoff and cyl should be unchanged.
353 			 */
354 			KASSERT(netbsdpartoff == 0);
355 			KASSERT(cyl == (LABELSECTOR / lp->d_secpercyl));
356 		}
357 	}
358 
359 /* writelabel: */
360 
361 /*	printf("writedisklabel: Reading disklabel addr=%08x\n",
362 	     netbsdpartoff * DEV_BSIZE);*/
363 
364 	/* next, dig out disk label */
365 
366 	bp->b_blkno = netbsdpartoff + LABELSECTOR;
367 	bp->b_cylinder = cyl;
368 	bp->b_bcount = lp->d_secsize;
369 	bp->b_oflags &= ~(BO_DONE);
370 	bp->b_flags |= B_READ;
371 	(*strat)(bp);
372 
373 	/* if successful, locate disk label within block and validate */
374 
375 	if ((error = biowait(bp)))
376 		goto done;
377 	for (dlp = (struct disklabel *)bp->b_data;
378 	    dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize - sizeof(*dlp));
379 	    dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
380 		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
381 		    dkcksum(dlp) == 0) {
382 			*dlp = *lp;
383 			bp->b_flags &= ~(B_READ);
384 			bp->b_oflags &= ~(BO_DONE);
385 			bp->b_flags |= B_WRITE;
386 			(*strat)(bp);
387 			error = biowait(bp);
388 			goto done;
389 		}
390 	}
391 
392 	error = ESRCH;
393 
394 done:
395 	brelse(bp, 0);
396 	return (error);
397 }
398 
399 /* End of disksubr.c */
400