Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / hp700 / hp700 / disksubr.c
blob3ec8f2fb81bd8a3c45ce9d90380a6679f350e160
1 /* $NetBSD: disksubr.c,v 1.25 2008/01/10 12:44:50 skrll Exp $ */
3 /* $OpenBSD: disksubr.c,v 1.6 2000/10/18 21:00:34 mickey Exp $ */
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.
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.
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.
35 * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
39 * Copyright (c) 1996 Theo de Raadt. All rights reserved.
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.
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.
63 * This disksubr.c module started to take it's 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.
67 * XXX HPUX disklabel is not understood yet.
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.25 2008/01/10 12:44:50 skrll Exp $");
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>
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);
87 * Try to read a standard BSD disklabel at a certain sector.
89 const char *
90 readbsdlabel(struct buf *bp, void (*strat)(struct buf *), int cyl, int sec,
91 int off, struct disklabel *lp, int spoofonly)
93 struct disklabel *dlp;
94 const char *msg = NULL;
95 u_int16_t cksum;
97 /* don't read the on-disk label if we are in spoofed-only mode */
98 if (spoofonly)
99 return (NULL);
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);
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);
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.
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;
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);
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.
152 * Returns null on success and an error string on failure.
154 const char *
155 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
156 struct cpu_disklabel *osdep)
158 int spoofonly = 0;
159 struct buf *bp = NULL;
160 const char *msg = "no disk label";
161 int i;
162 struct disklabel minilabel, fallbacklabel;
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";
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;
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 minilabel = fallbacklabel = *lp;
182 /* get a buffer and initialize it */
183 bp = geteblk((int)lp->d_secsize);
184 bp->b_dev = dev;
186 msg = readliflabel(bp, strat, lp, osdep, 0, 0, spoofonly);
188 #if defined(CD9660)
189 if (msg && iso_disklabelspoof(dev, strat, lp) == 0)
190 msg = NULL;
191 #endif
193 /* If there was an error, still provide a decent fake one. */
194 if (msg)
195 *lp = fallbacklabel;
197 if (bp) {
198 brelse(bp, BC_INVAL);
200 return (msg);
204 const char *
205 readliflabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp,
206 struct cpu_disklabel *osdep, int *partoffp, int *cylp, int spoofonly)
208 int fsoff;
210 /* read LIF volume header */
211 bp->b_blkno = btodb(HP700_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(HP700_LIF_VOLSTART) / lp->d_secpercyl;
216 (*strat)(bp);
218 if (biowait(bp)) {
219 if (partoffp)
220 *partoffp = -1;
221 return "LIF volume header I/O error";
224 memcpy(&osdep->lifvol, bp->b_data, sizeof(struct hp700_lifvol));
225 if (osdep->lifvol.vol_id != HP700_LIF_VOL_ID) {
226 fsoff = 0;
227 } else {
228 struct buf *dbp;
229 struct hp700_lifdir *p;
231 dbp = geteblk(HP700_LIF_DIRSIZE);
232 dbp->b_dev = bp->b_dev;
234 /* read LIF directory */
235 dbp->b_blkno = btodb(HP700_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 = (HP700_LIF_DIRSTART) / lp->d_secpercyl;
241 (*strat)(dbp);
243 if (biowait(dbp)) {
244 if (partoffp)
245 *partoffp = -1;
246 brelse(dbp, BC_INVAL);
248 return "LIF directory I/O error";
251 memcpy(osdep->lifdir, dbp->b_data, HP700_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[HP700_LIF_NUMDIR]; p++)
256 if (p->dir_type == HP700_LIF_DIR_FS)
257 fsoff = hp700_lifstodb(p->dir_addr);
259 /* if no suitable lifdir entry found assume 0 */
260 if (fsoff < 0)
261 fsoff = 0;
264 if (partoffp)
265 *partoffp = fsoff;
267 return readbsdlabel(bp, strat, 0, fsoff + LABELSECTOR, LABELOFFSET,
268 lp, spoofonly);
272 * Check new disk label for sensibility
273 * before setting it.
276 setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask,
277 struct cpu_disklabel *osdep)
279 int i;
280 struct partition *opp, *npp;
282 /* sanity clause */
283 if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 ||
284 (nlp->d_secsize % DEV_BSIZE) != 0)
285 return(EINVAL);
288 * XXX Nice thought, but it doesn't work, if the intention was to
289 * force a reread at the next *readdisklabel call. That does not
290 * happen. There's still some use for it though as you can pseudo-
291 * partition the disk.
293 * Special case to allow disklabel to be invalidated.
295 if (nlp->d_magic == 0xffffffff) {
296 *olp = *nlp;
297 return (0);
300 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
301 dkcksum(nlp) != 0)
302 return (EINVAL);
304 /* XXX missing check if other dos partitions will be overwritten */
306 while (openmask != 0) {
307 i = ffs((long)openmask) - 1;
308 openmask &= ~(1 << i);
309 if (nlp->d_npartitions <= i)
310 return (EBUSY);
311 opp = &olp->d_partitions[i];
312 npp = &nlp->d_partitions[i];
313 if (npp->p_offset != opp->p_offset ||
314 npp->p_size < opp->p_size)
315 return (EBUSY);
317 * Copy internally-set partition information
318 * if new label doesn't include it. XXX
320 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
321 npp->p_fstype = opp->p_fstype;
322 npp->p_fsize = opp->p_fsize;
323 npp->p_frag = opp->p_frag;
324 npp->p_cpg = opp->p_cpg;
327 nlp->d_checksum = 0;
328 nlp->d_checksum = dkcksum(nlp);
329 *olp = *nlp;
330 return (0);
335 * Write disk label back to device after modification.
338 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
339 struct cpu_disklabel *osdep)
341 const char *msg = "no disk label";
342 struct buf *bp;
343 struct disklabel dl;
344 struct cpu_disklabel cdl;
345 int labeloffset, error, partoff = 0, cyl = 0;
347 /* get a buffer and initialize it */
348 bp = geteblk((int)lp->d_secsize);
349 bp->b_dev = dev;
352 * I once played with the thought of using osdep->label{tag,sector}
353 * as a cache for knowing where (and what) to write. However, now I
354 * think it might be useful to reprobe if someone has written
355 * a newer disklabel of another type with disklabel(8) and -r.
357 dl = *lp;
358 msg = readliflabel(bp, strat, &dl, &cdl, &partoff, &cyl, 0);
359 labeloffset = LABELOFFSET;
361 if (msg) {
362 if (partoff == -1)
363 return EIO;
365 /* Write it in the regular place with native byte order. */
366 labeloffset = LABELOFFSET;
367 bp->b_blkno = partoff + LABELSECTOR;
368 bp->b_cylinder = cyl;
369 bp->b_bcount = lp->d_secsize;
372 *(struct disklabel *)((char *)bp->b_data + labeloffset) = *lp;
374 bp->b_cflags = BC_BUSY;
375 bp->b_flags = B_WRITE;
376 (*strat)(bp);
377 error = biowait(bp);
379 brelse(bp, BC_INVAL);
380 return (error);