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 $ */
6 * Copyright (c) 1999 Michael Shalayeff
7 * Copyright (c) 1997 Niklas Hallqvist
8 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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
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
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>
76 #include <sys/device.h>
77 #include <sys/disklabel.h>
78 #include <sys/syslog.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.
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
;
97 /* don't read the on-disk label if we are in spoofed-only mode */
102 bp
->b_cylinder
= cyl
;
103 bp
->b_bcount
= lp
->d_secsize
;
104 bp
->b_cflags
= BC_BUSY
;
105 bp
->b_flags
= B_READ
;
109 /* if successful, locate disk label within block and validate */
111 /* XXX we return the faked label built so far */
112 msg
= "disk label I/O error";
117 * If off is negative, search until the end of the sector for
118 * the label, otherwise, just look at the specific location
121 dlp
= (struct disklabel
*)((char *)bp
->b_data
+ (off
>= 0 ? off
: 0));
123 if (dlp
->d_magic
!= DISKMAGIC
|| dlp
->d_magic2
!= DISKMAGIC
) {
125 msg
= "no disk label";
127 cksum
= dkcksum(dlp
);
128 if (dlp
->d_npartitions
> MAXPARTITIONS
|| cksum
!= 0) {
129 msg
= "disk label corrupted";
138 dlp
= (struct disklabel
*)((char *)dlp
+ sizeof(int32_t));
139 } while (dlp
<= (struct disklabel
*)((char *)bp
->b_data
+
140 lp
->d_secsize
- sizeof(*dlp
)));
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.
155 readdisklabel(dev_t dev
, void (*strat
)(struct buf
*), struct disklabel
*lp
,
156 struct cpu_disklabel
*osdep
)
159 struct buf
*bp
= NULL
;
160 const char *msg
= "no disk label";
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
);
186 msg
= readliflabel(bp
, strat
, lp
, osdep
, 0, 0, spoofonly
);
189 if (msg
&& iso_disklabelspoof(dev
, strat
, lp
) == 0)
193 /* If there was an error, still provide a decent fake one. */
198 brelse(bp
, BC_INVAL
);
205 readliflabel(struct buf
*bp
, void (*strat
)(struct buf
*), struct disklabel
*lp
,
206 struct cpu_disklabel
*osdep
, int *partoffp
, int *cylp
, int spoofonly
)
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
;
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
) {
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
;
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 */
267 return readbsdlabel(bp
, strat
, 0, fsoff
+ LABELSECTOR
, LABELOFFSET
,
272 * Check new disk label for sensibility
276 setdisklabel(struct disklabel
*olp
, struct disklabel
*nlp
, u_long openmask
,
277 struct cpu_disklabel
*osdep
)
280 struct partition
*opp
, *npp
;
283 if (nlp
->d_secpercyl
== 0 || nlp
->d_secsize
== 0 ||
284 (nlp
->d_secsize
% DEV_BSIZE
) != 0)
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) {
300 if (nlp
->d_magic
!= DISKMAGIC
|| nlp
->d_magic2
!= DISKMAGIC
||
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
)
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
)
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
;
328 nlp
->d_checksum
= dkcksum(nlp
);
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";
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
);
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.
358 msg
= readliflabel(bp
, strat
, &dl
, &cdl
, &partoff
, &cyl
, 0);
359 labeloffset
= LABELOFFSET
;
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
;
379 brelse(bp
, BC_INVAL
);