xref: /netbsd/sys/arch/pmax/pmax/disksubr.c (revision bf9ec67e)
1 /*	$NetBSD: disksubr.c,v 1.36 2002/03/05 09:40:41 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 "opt_compat_ultrix.h"
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/buf.h>
43 #include <sys/disk.h>
44 #include <sys/disklabel.h>
45 
46 #ifdef COMPAT_ULTRIX
47 #include <dev/dec/dec_boot.h>
48 #include <ufs/ufs/dinode.h>		/* XXX for fs.h */
49 #include <ufs/ffs/fs.h>			/* XXX for BBSIZE & SBSIZE */
50 
51 char	*compat_label __P((dev_t dev, void (*strat) __P((struct buf *bp)),
52 	    struct disklabel *lp, struct cpu_disklabel *osdep));	/* XXX */
53 
54 #endif
55 
56 /*
57  * Attempt to read a disk label from a device
58  * using the indicated strategy routine.
59  * The label must be partly set up before this:
60  * secpercyl and anything required in the strategy routine
61  * (e.g., sector size) must be filled in before calling us.
62  * Returns null on success and an error string on failure.
63  */
64 char *
65 readdisklabel(dev, strat, lp, osdep)
66 	dev_t dev;
67 	void (*strat) __P((struct buf *bp));
68 	struct disklabel *lp;
69 	struct cpu_disklabel *osdep;
70 {
71 	struct buf *bp;
72 	struct disklabel *dlp;
73 	char *msg = NULL;
74 
75 	if (lp->d_secperunit == 0)
76 		lp->d_secperunit = 0x1fffffff;
77 	lp->d_npartitions = 1;
78 	if (lp->d_partitions[0].p_size == 0)
79 		lp->d_partitions[0].p_size = 0x1fffffff;
80 	lp->d_partitions[0].p_offset = 0;
81 
82 	bp = geteblk((int)lp->d_secsize);
83 	bp->b_dev = dev;
84 	bp->b_blkno = LABELSECTOR;
85 	bp->b_bcount = lp->d_secsize;
86 	bp->b_flags |= B_READ;
87 	bp->b_cylinder = LABELSECTOR / lp->d_secpercyl;
88 	(*strat)(bp);
89 	if (biowait(bp)) {
90 		msg = "I/O error";
91 	} else for (dlp = (struct disklabel *)bp->b_data;
92 	    dlp <= (struct disklabel *)(bp->b_data+DEV_BSIZE-sizeof(*dlp));
93 	    dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
94 		if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
95 			if (msg == NULL)
96 				msg = "no disk label";
97 		} else if (dlp->d_npartitions > MAXPARTITIONS ||
98 			   dkcksum(dlp) != 0)
99 			msg = "disk label corrupted";
100 		else {
101 			*lp = *dlp;
102 			msg = NULL;
103 			break;
104 		}
105 	}
106 	brelse(bp);
107 #ifdef COMPAT_ULTRIX
108 	/*
109 	 * If no NetBSD label was found, check for an Ultrix label and
110 	 * construct tne incore label from the Ultrix partition information.
111 	 */
112 	if (msg != NULL) {
113 		msg = compat_label(dev, strat, lp, osdep);
114 		if (msg == NULL) {
115 			printf("WARNING: using Ultrix partition information\n");
116 			/* set geometry? */
117 		}
118 	}
119 #endif
120 /* XXX If no NetBSD label or Ultrix label found, generate default label here */
121 	return (msg);
122 }
123 
124 #ifdef COMPAT_ULTRIX
125 /*
126  * Given a buffer bp, try and interpret it as an Ultrix disk label,
127  * putting the partition info into a native NetBSD label
128  */
129 char *
130 compat_label(dev, strat, lp, osdep)
131 	dev_t dev;
132 	void (*strat) __P((struct buf *bp));
133 	struct disklabel *lp;
134 	struct cpu_disklabel *osdep;
135 {
136 	dec_disklabel *dlp;
137 	struct buf *bp = NULL;
138 	char *msg = NULL;
139 
140 	bp = geteblk((int)lp->d_secsize);
141 	bp->b_dev = dev;
142 	bp->b_blkno = DEC_LABEL_SECTOR;
143 	bp->b_bcount = lp->d_secsize;
144 	bp->b_flags |= B_READ;
145 	bp->b_cylinder = DEC_LABEL_SECTOR / lp->d_secpercyl;
146 	(*strat)(bp);
147 
148 	if (biowait(bp)) {
149                 msg = "I/O error";
150 		goto done;
151 	}
152 
153 	for (dlp = (dec_disklabel *)bp->b_data;
154 	     dlp <= (dec_disklabel *)(bp->b_data+DEV_BSIZE-sizeof(*dlp));
155 	     dlp = (dec_disklabel *)((char *)dlp + sizeof(long))) {
156 
157 		int part;
158 
159 		if (dlp->magic != DEC_LABEL_MAGIC) {
160 			printf("label: %x\n",dlp->magic);
161 			msg = ((msg != NULL) ? msg: "no disk label");
162 			goto done;
163 		}
164 
165 #ifdef DIAGNOSTIC
166 /*XXX*/		printf("Interpreting Ultrix label\n");
167 #endif
168 
169 		lp->d_magic = DEC_LABEL_MAGIC;
170 		lp->d_npartitions = 0;
171 		strncpy(lp->d_packname, "Ultrix label", 16);
172 		lp->d_rpm = 3600;
173 		lp->d_interleave = 1;
174 		lp->d_flags = 0;
175 		lp->d_bbsize = BBSIZE;
176 		lp->d_sbsize = SBSIZE;
177 		for (part = 0;
178 		     part <((MAXPARTITIONS<DEC_NUM_DISK_PARTS) ?
179 			    MAXPARTITIONS : DEC_NUM_DISK_PARTS);
180 		     part++) {
181 			lp->d_partitions[part].p_size = dlp->map[part].num_blocks;
182 			lp->d_partitions[part].p_offset = dlp->map[part].start_block;
183 			lp->d_partitions[part].p_fsize = 1024;
184 			lp->d_partitions[part].p_fstype =
185 			  (part==1) ? FS_SWAP : FS_BSDFFS;
186 			lp->d_npartitions += 1;
187 
188 #ifdef DIAGNOSTIC
189 			printf(" Ultrix label rz%d%c: start %d len %d\n",
190 			       DISKUNIT(dev), "abcdefgh"[part],
191 			       lp->d_partitions[part].p_offset,
192 			       lp->d_partitions[part].p_size);
193 #endif
194 		}
195 		break;
196 	}
197 
198 done:
199 	brelse(bp);
200 	return (msg);
201 }
202 #endif /* COMPAT_ULTRIX */
203 
204 
205 /*
206  * Check new disk label for sensibility
207  * before setting it.
208  */
209 int
210 setdisklabel(olp, nlp, openmask, osdep)
211 	struct disklabel *olp, *nlp;
212 	u_long openmask;
213 	struct cpu_disklabel *osdep;
214 {
215 	int i;
216 	struct partition *opp, *npp;
217 
218 	if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
219 	    dkcksum(nlp) != 0)
220 		return (EINVAL);
221 	while ((i = ffs(openmask)) != 0) {
222 		i--;
223 		openmask &= ~(1 << i);
224 		if (nlp->d_npartitions <= i)
225 			return (EBUSY);
226 		opp = &olp->d_partitions[i];
227 		npp = &nlp->d_partitions[i];
228 		if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
229 			return (EBUSY);
230 		/*
231 		 * Copy internally-set partition information
232 		 * if new label doesn't include it.		XXX
233 		 */
234 		if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
235 			npp->p_fstype = opp->p_fstype;
236 			npp->p_fsize = opp->p_fsize;
237 			npp->p_frag = opp->p_frag;
238 			npp->p_cpg = opp->p_cpg;
239 		}
240 	}
241  	nlp->d_checksum = 0;
242  	nlp->d_checksum = dkcksum(nlp);
243 	*olp = *nlp;
244 	return (0);
245 }
246 
247 /*
248  * Write disk label back to device after modification.
249  */
250 int
251 writedisklabel(dev, strat, lp, osdep)
252 	dev_t dev;
253 	void (*strat) __P((struct buf *bp));
254 	struct disklabel *lp;
255 	struct cpu_disklabel *osdep;
256 {
257 	struct buf *bp;
258 	struct disklabel *dlp;
259 	int labelpart;
260 	int error = 0;
261 
262 	labelpart = DISKPART(dev);
263 	if (lp->d_partitions[labelpart].p_offset != 0) {
264 		if (lp->d_partitions[0].p_offset != 0)
265 			return (EXDEV);			/* not quite right */
266 		labelpart = 0;
267 	}
268 	bp = geteblk((int)lp->d_secsize);
269 	bp->b_dev = makedev(major(dev), DISKMINOR(DISKUNIT(dev), labelpart));
270 	bp->b_blkno = LABELSECTOR;
271 	bp->b_bcount = lp->d_secsize;
272 	bp->b_flags |= B_READ;
273 	(*strat)(bp);
274 	if ((error = biowait(bp)) != 0)
275 		goto done;
276 	for (dlp = (struct disklabel *)bp->b_data;
277 	    dlp <= (struct disklabel *)
278 	      (bp->b_data + lp->d_secsize - sizeof(*dlp));
279 	    dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
280 		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
281 		    dkcksum(dlp) == 0) {
282 			*dlp = *lp;
283 			bp->b_flags &= ~(B_READ|B_DONE);
284 			bp->b_flags |= B_WRITE;
285 			(*strat)(bp);
286 			error = biowait(bp);
287 			goto done;
288 		}
289 	}
290 	error = ESRCH;
291 done:
292 	brelse(bp);
293 	return (error);
294 }
295 
296 /*
297  * UNTESTED !!
298  *
299  * Determine the size of the transfer, and make sure it is
300  * within the boundaries of the partition. Adjust transfer
301  * if needed, and signal errors or early completion.
302  */
303 int
304 bounds_check_with_label(bp, lp, wlabel)
305 	struct buf *bp;
306 	struct disklabel *lp;
307 	int wlabel;
308 {
309 
310 	struct partition *p = lp->d_partitions + DISKPART(bp->b_dev);
311 	int labelsect = lp->d_partitions[RAW_PART].p_offset;
312 	int maxsz = p->p_size;
313 	int sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
314 
315 	/* overwriting disk label ? */
316 	/* XXX should also protect bootstrap in first 8K */
317 	if (bp->b_blkno + p->p_offset <= LABELSECTOR + labelsect &&
318 	    (bp->b_flags & B_READ) == 0 && wlabel == 0) {
319 		bp->b_error = EROFS;
320 		goto bad;
321 	}
322 
323 	/* beyond partition? */
324 	if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
325 		/* if exactly at end of disk, return an EOF */
326 		if (bp->b_blkno == maxsz) {
327 			bp->b_resid = bp->b_bcount;
328 			return(0);
329 		}
330 		/* or truncate if part of it fits */
331 		sz = maxsz - bp->b_blkno;
332 		if (sz <= 0) {
333 			bp->b_error = EINVAL;
334 			goto bad;
335 		}
336 		bp->b_bcount = sz << DEV_BSHIFT;
337 	}
338 
339 	/* calculate cylinder for disksort to order transfers with */
340 	bp->b_resid = (bp->b_blkno + p->p_offset) / lp->d_secpercyl;
341 	return(1);
342 bad:
343 	bp->b_flags |= B_ERROR;
344 	return(-1);
345 }
346