xref: /netbsd/sys/arch/news68k/news68k/disksubr.c (revision bf9ec67e)
1 /*	$NetBSD: disksubr.c,v 1.9 2002/03/05 09:40:40 simonb Exp $	*/
2 
3 /*
4  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. 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 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/buf.h>
41 #include <sys/device.h>
42 #include <sys/disk.h>
43 #include <sys/disklabel.h>
44 
45 /*
46  * Attempt to read a disk label from a device
47  * using the indicated strategy routine.
48  * The label must be partly set up before this:
49  * secpercyl and anything required in the strategy routine
50  * (e.g., sector size) must be filled in before calling us.
51  * Returns null on success and an error string on failure.
52  */
53 char *
54 readdisklabel(dev, strat, lp, osdep)
55 	dev_t dev;
56 	void (*strat) __P((struct buf *bp));
57 	struct disklabel *lp;
58 	struct cpu_disklabel *osdep;
59 {
60 	struct buf *bp;
61 	struct disklabel *dlp;
62 	char *msg = NULL;
63 
64 	if (lp->d_secperunit == 0)
65 		lp->d_secperunit = 0x1fffffff;
66 	lp->d_npartitions = 1;
67 	if (lp->d_partitions[0].p_size == 0)
68 		lp->d_partitions[0].p_size = 0x1fffffff;
69 	lp->d_partitions[0].p_offset = 0;
70 
71 	bp = geteblk((int)lp->d_secsize);
72 	bp->b_dev = dev;
73 	bp->b_blkno = LABELSECTOR;
74 	bp->b_bcount = lp->d_secsize;
75 	bp->b_flags |= B_READ;
76 	bp->b_cylinder = LABELSECTOR / lp->d_secpercyl;
77 	(*strat)(bp);
78 	if (biowait(bp)) {
79 		msg = "I/O error";
80 	} else for (dlp = (struct disklabel *)bp->b_data;
81 	    dlp <= (struct disklabel *)(bp->b_data+DEV_BSIZE-sizeof(*dlp));
82 	    dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
83 		if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
84 			if (msg == NULL)
85 				msg = "no disk label";
86 		} else if (dlp->d_npartitions > MAXPARTITIONS ||
87 			   dkcksum(dlp) != 0)
88 			msg = "disk label corrupted";
89 		else {
90 			*lp = *dlp;
91 			msg = NULL;
92 			break;
93 		}
94 	}
95 	brelse(bp);
96 	return (msg);
97 }
98 
99 /*
100  * Check new disk label for sensibility
101  * before setting it.
102  */
103 int
104 setdisklabel(olp, nlp, openmask, osdep)
105 	struct disklabel *olp, *nlp;
106 	u_long openmask;
107 	struct cpu_disklabel *osdep;
108 {
109 	int i;
110 	struct partition *opp, *npp;
111 
112 	if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
113 	    dkcksum(nlp) != 0)
114 		return (EINVAL);
115 	while ((i = ffs(openmask)) != 0) {
116 		i--;
117 		openmask &= ~(1 << i);
118 		if (nlp->d_npartitions <= i)
119 			return (EBUSY);
120 		opp = &olp->d_partitions[i];
121 		npp = &nlp->d_partitions[i];
122 		if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
123 			return (EBUSY);
124 		/*
125 		 * Copy internally-set partition information
126 		 * if new label doesn't include it.		XXX
127 		 */
128 		if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
129 			npp->p_fstype = opp->p_fstype;
130 			npp->p_fsize = opp->p_fsize;
131 			npp->p_frag = opp->p_frag;
132 			npp->p_cpg = opp->p_cpg;
133 		}
134 	}
135  	nlp->d_checksum = 0;
136  	nlp->d_checksum = dkcksum(nlp);
137 	*olp = *nlp;
138 	return (0);
139 }
140 
141 /*
142  * Write disk label back to device after modification.
143  */
144 int
145 writedisklabel(dev, strat, lp, osdep)
146 	dev_t dev;
147 	void (*strat) __P((struct buf *bp));
148 	struct disklabel *lp;
149 	struct cpu_disklabel *osdep;
150 {
151 	struct buf *bp;
152 	struct disklabel *dlp;
153 	int labelpart;
154 	int error = 0;
155 
156 	labelpart = DISKPART(dev);
157 	if (lp->d_partitions[labelpart].p_offset != 0) {
158 		if (lp->d_partitions[0].p_offset != 0)
159 			return (EXDEV);			/* not quite right */
160 		labelpart = 0;
161 	}
162 	bp = geteblk((int)lp->d_secsize);
163 	bp->b_dev = makedev(major(dev), DISKMINOR(DISKUNIT(dev), labelpart));
164 	bp->b_blkno = LABELSECTOR;
165 	bp->b_bcount = lp->d_secsize;
166 	bp->b_flags |= B_READ;
167 	(*strat)(bp);
168 	if ((error = biowait(bp)) != 0)
169 		goto done;
170 	for (dlp = (struct disklabel *)bp->b_data;
171 	    dlp <= (struct disklabel *)
172 	      (bp->b_data + lp->d_secsize - sizeof(*dlp));
173 	    dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
174 		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
175 		    dkcksum(dlp) == 0) {
176 			*dlp = *lp;
177 			bp->b_flags &= ~(B_READ|B_DONE);
178 			bp->b_flags |= B_WRITE;
179 			(*strat)(bp);
180 			error = biowait(bp);
181 			goto done;
182 		}
183 	}
184 	error = ESRCH;
185 done:
186 	brelse(bp);
187 	return (error);
188 }
189 
190 /*
191  * UNTESTED !!
192  *
193  * Determine the size of the transfer, and make sure it is
194  * within the boundaries of the partition. Adjust transfer
195  * if needed, and signal errors or early completion.
196  */
197 int
198 bounds_check_with_label(bp, lp, wlabel)
199 	struct buf *bp;
200 	struct disklabel *lp;
201 	int wlabel;
202 {
203 
204 	struct partition *p = lp->d_partitions + DISKPART(bp->b_dev);
205 	int labelsect = lp->d_partitions[0].p_offset;
206 	int maxsz = p->p_size;
207 	int sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
208 
209 	/* overwriting disk label ? */
210 	/* XXX should also protect bootstrap in first 8K */
211 	if (bp->b_blkno + p->p_offset <= LABELSECTOR + labelsect &&
212 	    (bp->b_flags & B_READ) == 0 && wlabel == 0) {
213 		bp->b_error = EROFS;
214 		goto bad;
215 	}
216 
217 	/* beyond partition? */
218 	if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
219 		/* if exactly at end of disk, return an EOF */
220 		if (bp->b_blkno == maxsz) {
221 			bp->b_resid = bp->b_bcount;
222 			return(0);
223 		}
224 		/* or truncate if part of it fits */
225 		sz = maxsz - bp->b_blkno;
226 		if (sz <= 0) {
227 			bp->b_error = EINVAL;
228 			goto bad;
229 		}
230 		bp->b_bcount = sz << DEV_BSHIFT;
231 	}
232 
233 	/* calculate cylinder for disksort to order transfers with */
234 	bp->b_resid = (bp->b_blkno + p->p_offset) / lp->d_secpercyl;
235 	return(1);
236 bad:
237 	bp->b_flags |= B_ERROR;
238 	return(-1);
239 }
240