1 /* $NetBSD: disksubr.c,v 1.11 2009/03/14 21:04:23 dsl Exp $ */
4 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * Copyright (c) 1994, 1995 Gordon W. Ross
33 * Copyright (c) 1994 Theo de Raadt
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 #include <sys/cdefs.h>
58 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.11 2009/03/14 21:04:23 dsl Exp $");
60 #include <sys/param.h>
61 #include <sys/systm.h>
63 #include <sys/ioccom.h>
64 #include <sys/device.h>
65 #include <sys/disklabel.h>
67 #include <sys/dkbad.h>
69 #include <dev/sun/disklabel.h>
72 #error "Default value of LABELSECTOR no longer zero?"
75 static const char *disklabel_sun_to_bsd(char *, struct disklabel
*);
76 static int disklabel_bsd_to_sun(struct disklabel
*, char *);
79 * Attempt to read a disk label from a device
80 * using the indicated strategy routine.
81 * The label must be partly set up before this:
82 * secpercyl, secsize and anything required for a block i/o read
83 * operation in the driver's strategy/start routines
84 * must be filled in before calling us.
86 * Return buffer for use in signalling errors if requested.
88 * Returns null on success and an error string on failure.
91 readdisklabel(dev_t dev
, void (*strat
)(struct buf
*), struct disklabel
*lp
, struct cpu_disklabel
*clp
)
94 struct disklabel
*dlp
;
95 struct sun_disklabel
*slp
;
98 /* minimal requirements for archtypal disk label */
99 if (lp
->d_secperunit
== 0)
100 lp
->d_secperunit
= 0x1fffffff;
101 if (lp
->d_npartitions
== 0) {
102 lp
->d_npartitions
= RAW_PART
+ 1;
103 if (lp
->d_partitions
[RAW_PART
].p_size
== 0)
104 lp
->d_partitions
[RAW_PART
].p_size
= 0x1fffffff;
105 lp
->d_partitions
[RAW_PART
].p_offset
= 0;
108 /* obtain buffer to probe drive with */
109 bp
= geteblk((int)lp
->d_secsize
);
111 /* next, dig out disk label */
113 bp
->b_blkno
= LABELSECTOR
;
115 bp
->b_bcount
= lp
->d_secsize
;
116 bp
->b_flags
|= B_READ
;
119 /* if successful, locate disk label within block and validate */
122 /* Save the whole block in case it has info we need. */
123 memcpy(clp
->cd_block
, bp
->b_data
, sizeof(clp
->cd_block
));
127 return ("disk label read error");
129 /* Check for a NetBSD disk label at LABELOFFSET */
130 dlp
= (struct disklabel
*) (clp
->cd_block
+ LABELOFFSET
);
131 if (dlp
->d_magic
== DISKMAGIC
) {
133 return ("NetBSD disk label corrupted");
138 /* Check for a Sun disk label (for PROM compatibility). */
139 slp
= (struct sun_disklabel
*) clp
->cd_block
;
140 if (slp
->sl_magic
== SUN_DKMAGIC
)
141 return (disklabel_sun_to_bsd(clp
->cd_block
, lp
));
144 * Check for a NetBSD disk label somewhere in LABELSECTOR
145 * (compat with others big-endian boxes)
147 for (dlp
= (struct disklabel
*)clp
->cd_block
;
148 dlp
<= (struct disklabel
*)((char *)clp
->cd_block
+
149 DEV_BSIZE
- sizeof(*dlp
));
150 dlp
= (struct disklabel
*)((char *)dlp
+ sizeof(long))) {
151 if (dlp
->d_magic
!= DISKMAGIC
|| dlp
->d_magic2
!= DISKMAGIC
) {
154 if (dlp
->d_npartitions
> MAXPARTITIONS
|| dkcksum(dlp
) != 0)
155 return("NetBSD disk label corrupted");
162 memset(clp
->cd_block
, 0, sizeof(clp
->cd_block
));
163 return ("no disk label");
167 * Check new disk label for sensibility
171 setdisklabel(struct disklabel
*olp
, struct disklabel
*nlp
, u_long openmask
, struct cpu_disklabel
*clp
)
174 struct partition
*opp
, *npp
;
177 if (nlp
->d_secpercyl
== 0 || nlp
->d_secsize
== 0 ||
178 (nlp
->d_secsize
% DEV_BSIZE
) != 0)
181 /* special case to allow disklabel to be invalidated */
182 if (nlp
->d_magic
== 0xffffffff) {
187 if (nlp
->d_magic
!= DISKMAGIC
|| nlp
->d_magic2
!= DISKMAGIC
||
191 while ((i
= ffs(openmask
)) != 0) {
193 openmask
&= ~(1 << i
);
194 if (nlp
->d_npartitions
<= i
)
196 opp
= &olp
->d_partitions
[i
];
197 npp
= &nlp
->d_partitions
[i
];
198 if (npp
->p_offset
!= opp
->p_offset
|| npp
->p_size
< opp
->p_size
)
207 * Write disk label back to device after modification.
208 * Current label is already in clp->cd_block[]
211 writedisklabel(dev_t dev
, void (*strat
)(struct buf
*), struct disklabel
*lp
, struct cpu_disklabel
*clp
)
215 struct disklabel
*dlp
;
216 struct sun_disklabel
*slp
;
219 * Embed native label in a piece of wasteland.
221 if (sizeof(struct disklabel
) > sizeof slp
->sl_bsdlabel
)
224 slp
= (struct sun_disklabel
*)clp
->cd_block
;
225 memset(slp
->sl_bsdlabel
, 0, sizeof(slp
->sl_bsdlabel
));
226 dlp
= (struct disklabel
*)slp
->sl_bsdlabel
;
229 /* Build a SunOS compatible label around the native label */
230 error
= disklabel_bsd_to_sun(lp
, clp
->cd_block
);
234 /* Get a buffer and copy the new label into it. */
235 bp
= geteblk((int)lp
->d_secsize
);
236 memcpy(bp
->b_data
, clp
->cd_block
, sizeof(clp
->cd_block
));
238 /* Write out the updated label. */
240 bp
->b_blkno
= LABELSECTOR
;
242 bp
->b_bcount
= lp
->d_secsize
;
243 bp
->b_flags
|= B_WRITE
;
251 /************************************************************************
253 * The rest of this was taken from arch/sparc/scsi/sun_disklabel.c
254 * and then substantially rewritten by Gordon W. Ross
256 ************************************************************************/
258 /* What partition types to assume for Sun disklabels: */
263 FS_OTHER
, /* c - whole disk */
272 * Given a SunOS disk label, set lp to a BSD disk label.
273 * Returns NULL on success, else an error string.
275 * The BSD label is cleared out before this is called.
278 disklabel_sun_to_bsd(char *cp
, struct disklabel
*lp
)
280 struct sun_disklabel
*sl
;
281 struct partition
*npp
;
282 struct sun_dkpart
*spp
;
284 u_short cksum
, *sp1
, *sp2
;
286 sl
= (struct sun_disklabel
*)cp
;
288 /* Verify the XOR check. */
290 sp2
= (u_short
*)(sl
+ 1);
295 return("SunOS disk label, bad checksum");
297 /* Format conversion. */
298 lp
->d_magic
= DISKMAGIC
;
299 lp
->d_magic2
= DISKMAGIC
;
300 memcpy(lp
->d_packname
, sl
->sl_text
, sizeof(lp
->d_packname
));
303 lp
->d_nsectors
= sl
->sl_nsectors
;
304 lp
->d_ntracks
= sl
->sl_ntracks
;
305 lp
->d_ncylinders
= sl
->sl_ncylinders
;
307 secpercyl
= sl
->sl_nsectors
* sl
->sl_ntracks
;
308 lp
->d_secpercyl
= secpercyl
;
309 lp
->d_secperunit
= secpercyl
* sl
->sl_ncylinders
;
311 lp
->d_sparespercyl
= sl
->sl_sparespercyl
;
312 lp
->d_acylinders
= sl
->sl_acylinders
;
313 lp
->d_rpm
= sl
->sl_rpm
;
314 lp
->d_interleave
= sl
->sl_interleave
;
316 lp
->d_npartitions
= 8;
317 /* These are as defined in <ufs/ffs/fs.h> */
318 lp
->d_bbsize
= 8192; /* XXX */
319 lp
->d_sbsize
= 8192; /* XXX */
321 for (i
= 0; i
< 8; i
++) {
322 spp
= &sl
->sl_part
[i
];
323 npp
= &lp
->d_partitions
[i
];
324 npp
->p_offset
= spp
->sdkp_cyloffset
* secpercyl
;
325 npp
->p_size
= spp
->sdkp_nsectors
;
326 if (npp
->p_size
== 0) {
327 npp
->p_fstype
= FS_UNUSED
;
329 npp
->p_fstype
= sun_fstypes
[i
];
330 if (npp
->p_fstype
== FS_BSDFFS
) {
332 * The sun label does not store the FFS fields,
333 * so just set them with default values here.
343 lp
->d_checksum
= dkcksum(lp
);
348 * Given a BSD disk label, update the Sun disklabel
349 * pointed to by cp with the new info. Note that the
350 * Sun disklabel may have other info we need to keep.
351 * Returns zero or error code.
354 disklabel_bsd_to_sun(struct disklabel
*lp
, char *cp
)
356 struct sun_disklabel
*sl
;
357 struct partition
*npp
;
358 struct sun_dkpart
*spp
;
360 u_short cksum
, *sp1
, *sp2
;
362 if (lp
->d_secsize
!= 512)
365 sl
= (struct sun_disklabel
*)cp
;
370 memcpy(sl
->sl_text
, lp
->d_packname
, sizeof(lp
->d_packname
));
371 sl
->sl_rpm
= lp
->d_rpm
;
372 sl
->sl_pcylinders
= lp
->d_ncylinders
+ lp
->d_acylinders
; /* XXX */
373 sl
->sl_sparespercyl
= lp
->d_sparespercyl
;
374 sl
->sl_interleave
= lp
->d_interleave
;
375 sl
->sl_ncylinders
= lp
->d_ncylinders
;
376 sl
->sl_acylinders
= lp
->d_acylinders
;
377 sl
->sl_ntracks
= lp
->d_ntracks
;
378 sl
->sl_nsectors
= lp
->d_nsectors
;
380 secpercyl
= sl
->sl_nsectors
* sl
->sl_ntracks
;
381 for (i
= 0; i
< 8; i
++) {
382 spp
= &sl
->sl_part
[i
];
383 npp
= &lp
->d_partitions
[i
];
386 * SunOS partitions must start on a cylinder boundary.
387 * Note this restriction is forced upon NetBSD/sparc
388 * labels too, since we want to keep both labels
391 if (npp
->p_offset
% secpercyl
)
393 spp
->sdkp_cyloffset
= npp
->p_offset
/ secpercyl
;
394 spp
->sdkp_nsectors
= npp
->p_size
;
396 sl
->sl_magic
= SUN_DKMAGIC
;
398 /* Compute the XOR check. */
400 sp2
= (u_short
*)(sl
+ 1);
401 sl
->sl_cksum
= cksum
= 0;
404 sl
->sl_cksum
= cksum
;
410 * Search the bad sector table looking for the specified sector.
411 * Return index if found.
412 * Return -1 if not found.
415 isbad(struct dkbad
*bt
, int cyl
, int trk
, int sec
)
420 blk
= ((long)cyl
<< 16) + (trk
<< 8) + sec
;
421 for (i
= 0; i
< 126; i
++) {
422 bblk
= ((long)bt
->bt_bad
[i
].bt_cyl
<< 16) +
423 bt
->bt_bad
[i
].bt_trksec
;
426 if (blk
< bblk
|| bblk
< 0)