Home | History | Annotate | Line # | Download | only in hppa
      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 *
     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 *
    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 *
    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
    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