xref: /netbsd-src/sys/arch/hppa/hppa/disksubr.c (revision 3560e5b35e332af544b58cfb41ff49d9bfb64ecb)
1 /*	$NetBSD: disksubr.c,v 1.4 2019/04/17 20:46:38 skrll Exp $	*/
2 
3 /*	$OpenBSD: disksubr.c,v 1.6 2000/10/18 21:00:34 mickey Exp $	*/
4 
5 /*
6  * Copyright (c) 1999 Michael Shalayeff
7  * Copyright (c) 1997 Niklas Hallqvist
8  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	@(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
36  */
37 
38 /*
39  * Copyright (c) 1996 Theo de Raadt.  All rights reserved.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
51  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
52  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
54  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
55  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
59  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60  */
61 
62 /*
63  * This disksubr.c module started to take its present form on OpenBSD/alpha
64  * but it was always thought it should be made completely MI and not need to
65  * be in that alpha-specific tree at all.
66  *
67  * XXX HPUX disklabel is not understood yet.
68  */
69 
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.4 2019/04/17 20:46:38 skrll Exp $");
72 
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/buf.h>
76 #include <sys/device.h>
77 #include <sys/disklabel.h>
78 #include <sys/syslog.h>
79 #include <sys/disk.h>
80 
81 const char *readliflabel(struct buf *, void (*)(struct buf *),
82     struct disklabel *, struct cpu_disklabel *, int *, int *, int);
83 const char *readbsdlabel(struct buf *, void (*)(struct buf *), int,
84     int, int, struct disklabel *, int);
85 
86 /*
87  * Try to read a standard BSD disklabel at a certain sector.
88  */
89 const char *
readbsdlabel(struct buf * bp,void (* strat)(struct buf *),int cyl,int sec,int off,struct disklabel * lp,int spoofonly)90 readbsdlabel(struct buf *bp, void (*strat)(struct buf *), int cyl, int sec,
91     int off, struct disklabel *lp, int spoofonly)
92 {
93 	struct disklabel *dlp;
94 	const char *msg = NULL;
95 	uint16_t cksum;
96 
97 	/* don't read the on-disk label if we are in spoofed-only mode */
98 	if (spoofonly)
99 		return (NULL);
100 
101 	bp->b_blkno = sec;
102 	bp->b_cylinder = cyl;
103 	bp->b_bcount = lp->d_secsize;
104 	bp->b_cflags = BC_BUSY;
105 	bp->b_flags = B_READ;
106 	bp->b_oflags = 0;
107 	(*strat)(bp);
108 
109 	/* if successful, locate disk label within block and validate */
110 	if (biowait(bp)) {
111 		/* XXX we return the faked label built so far */
112 		msg = "disk label I/O error";
113 		return (msg);
114 	}
115 
116 	/*
117 	 * If off is negative, search until the end of the sector for
118 	 * the label, otherwise, just look at the specific location
119 	 * we're given.
120 	 */
121 	dlp = (struct disklabel *)((char *)bp->b_data + (off >= 0 ? off : 0));
122 	do {
123 		if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
124 			if (msg == NULL)
125 				msg = "no disk label";
126 		} else {
127 			cksum = dkcksum(dlp);
128 			if (dlp->d_npartitions > MAXPARTITIONS || cksum != 0) {
129 				msg = "disk label corrupted";
130 			} else {
131 				*lp = *dlp;
132 				msg = NULL;
133 				break;
134 			}
135 		}
136 		if (off >= 0)
137 			break;
138 		dlp = (struct disklabel *)((char *)dlp + sizeof(int32_t));
139 	} while (dlp <= (struct disklabel *)((char *)bp->b_data +
140 		 lp->d_secsize - sizeof(*dlp)));
141 	return (msg);
142 }
143 
144 /*
145  * Attempt to read a disk label from a device
146  * using the indicated strategy routine.
147  * The label must be partly set up before this:
148  * secpercyl, secsize and anything required for a block i/o read
149  * operation in the driver's strategy/start routines
150  * must be filled in before calling us.
151  *
152  * Returns null on success and an error string on failure.
153  */
154 const char *
readdisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)155 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
156     struct cpu_disklabel *osdep)
157 {
158 	int spoofonly = 0;
159 	struct buf *bp = NULL;
160 	const char *msg = "no disk label";
161 	int i;
162 	struct disklabel fallbacklabel;
163 
164 	/* minimal requirements for archetypal disk label */
165 	if (lp->d_secsize == 0)
166 		lp->d_secsize = DEV_BSIZE;
167 	if (lp->d_secperunit == 0)
168 		lp->d_secperunit = 0x1fffffff;
169 	if (lp->d_secpercyl == 0)
170 		return "invalid geometry";
171 
172 	lp->d_npartitions = RAW_PART + 1;
173 	for (i = 0; i < RAW_PART; i++) {
174 		lp->d_partitions[i].p_size = 0;
175 		lp->d_partitions[i].p_offset = 0;
176 	}
177 	if (lp->d_partitions[i].p_size == 0)
178 		lp->d_partitions[i].p_size = 0x1fffffff;
179 	lp->d_partitions[i].p_offset = 0;
180 	fallbacklabel = *lp;
181 
182 	/* get a buffer and initialize it */
183 	bp = geteblk((int)lp->d_secsize);
184 	bp->b_dev = dev;
185 
186 	msg = readliflabel(bp, strat, lp, osdep, 0, 0, spoofonly);
187 
188 #if defined(CD9660)
189 	if (msg && iso_disklabelspoof(dev, strat, lp) == 0)
190 		msg = NULL;
191 #endif
192 
193 	/* If there was an error, still provide a decent fake one.  */
194 	if (msg)
195 		*lp = fallbacklabel;
196 
197 	if (bp) {
198 		brelse(bp, BC_INVAL);
199 	}
200 	return (msg);
201 }
202 
203 
204 const char *
readliflabel(struct buf * bp,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep,int * partoffp,int * cylp,int spoofonly)205 readliflabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp,
206     struct cpu_disklabel *osdep, int *partoffp, int *cylp, int spoofonly)
207 {
208 	int fsoff;
209 
210 	/* read LIF volume header */
211 	bp->b_blkno = btodb(HPPA_LIF_VOLSTART);
212 	bp->b_bcount = lp->d_secsize;
213 	bp->b_cflags = BC_BUSY;
214 	bp->b_flags = B_READ;
215 	bp->b_cylinder = btodb(HPPA_LIF_VOLSTART) / lp->d_secpercyl;
216 	(*strat)(bp);
217 
218 	if (biowait(bp)) {
219 		if (partoffp)
220 			*partoffp = -1;
221 		return "LIF volume header I/O error";
222 	}
223 
224 	memcpy(&osdep->lifvol, bp->b_data, sizeof(struct hppa_lifvol));
225 	if (osdep->lifvol.vol_id != HPPA_LIF_VOL_ID) {
226 		fsoff = 0;
227 	} else {
228 		struct buf *dbp;
229 		struct hppa_lifdir *p;
230 
231 		dbp = geteblk(lp->d_secsize);
232 		dbp->b_dev = bp->b_dev;
233 
234 		/* read LIF directory */
235 		dbp->b_blkno = btodb(HPPA_LIF_DIRSTART);
236 		dbp->b_bcount = lp->d_secsize;
237 		dbp->b_cflags = BC_BUSY;
238 		dbp->b_flags = B_READ;
239 		dbp->b_cylinder = (HPPA_LIF_DIRSTART) / lp->d_secpercyl;
240 
241 		(*strat)(dbp);
242 
243 		if (biowait(dbp)) {
244 			if (partoffp)
245 				*partoffp = -1;
246 			brelse(dbp, BC_INVAL);
247 
248 			return "LIF directory I/O error";
249 		}
250 
251 		memcpy(osdep->lifdir, dbp->b_data, HPPA_LIF_DIRSIZE);
252 		brelse(dbp, BC_INVAL);
253 		/* scan for LIF_DIR_FS dir entry */
254 		for (fsoff = -1,  p = &osdep->lifdir[0];
255 		     fsoff < 0 && p < &osdep->lifdir[HPPA_LIF_NUMDIR]; p++)
256 			if (p->dir_type == HPPA_LIF_DIR_FS)
257 				fsoff = hppa_lifstodb(p->dir_addr);
258 
259 		/* if no suitable lifdir entry found assume 0 */
260 		if (fsoff < 0)
261 			fsoff = 0;
262 	}
263 
264 	if (partoffp)
265 		*partoffp = fsoff;
266 
267 	return readbsdlabel(bp, strat, 0,  fsoff + LABELSECTOR, LABELOFFSET,
268 	    lp, spoofonly);
269 }
270 
271 /*
272  * Write disk label back to device after modification.
273  */
274 int
writedisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)275 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
276     struct cpu_disklabel *osdep)
277 {
278 	const char *msg = "no disk label";
279 	struct buf *bp;
280 	struct disklabel dl;
281 	struct cpu_disklabel cdl;
282 	int labeloffset, error, partoff = 0, cyl = 0;
283 
284 	/* get a buffer and initialize it */
285 	bp = geteblk((int)lp->d_secsize);
286 	bp->b_dev = dev;
287 
288 	/*
289 	 * I once played with the thought of using osdep->label{tag,sector}
290 	 * as a cache for knowing where (and what) to write.  However, now I
291 	 * think it might be useful to reprobe if someone has written
292 	 * a newer disklabel of another type with disklabel(8) and -r.
293 	 */
294 	dl = *lp;
295 	msg = readliflabel(bp, strat, &dl, &cdl, &partoff, &cyl, 0);
296 	labeloffset = LABELOFFSET;
297 
298 	if (msg) {
299 		if (partoff == -1)
300 			return EIO;
301 
302 		/* Write it in the regular place with native byte order. */
303 		labeloffset = LABELOFFSET;
304 		bp->b_blkno = partoff + LABELSECTOR;
305 		bp->b_cylinder = cyl;
306 		bp->b_bcount = lp->d_secsize;
307 	}
308 
309 	*(struct disklabel *)((char *)bp->b_data + labeloffset) = *lp;
310 
311 	bp->b_cflags = BC_BUSY;
312 	bp->b_flags = B_WRITE;
313 	(*strat)(bp);
314 	error = biowait(bp);
315 
316 	brelse(bp, BC_INVAL);
317 	return (error);
318 }
319