xref: /netbsd/sys/arch/next68k/next68k/disksubr.c (revision c4a72b64)
1 /*	$NetBSD: disksubr.c,v 1.9 2002/07/11 16:03:15 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1982, 1986, 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  * (c) UNIX System Laboratories, Inc.
7  * All or some portions of this file are derived from material licensed
8  * to the University of California by American Telephone and Telegraph
9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10  * the permission of UNIX System Laboratories, Inc.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *	This product includes software developed by the University of
23  *	California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *	@(#)ufs_disksubr.c	8.5 (Berkeley) 1/21/94
41  */
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/buf.h>
46 #define FSTYPENAMES
47 #include <sys/disklabel.h>
48 #include <sys/syslog.h>
49 
50 #include <sys/disk.h>
51 
52 #include <ufs/ufs/dinode.h>             /* XXX for fs.h */
53 #include <ufs/ffs/fs.h>                 /* XXX for SBSIZE */
54 
55 #define	b_cylinder	b_resid
56 
57 static unsigned short nextstep_checksum __P((unsigned char *,
58 			unsigned char *));
59 static char * parse_nextstep_label __P((struct nextstep_disklabel *,
60 			struct disklabel *, struct cpu_disklabel *));
61 static int build_nextstep_label __P((struct nextstep_disklabel *,
62 			struct disklabel *, struct cpu_disklabel *));
63 
64 static unsigned short
65 nextstep_checksum(buf, limit)
66 	unsigned char *buf;
67 	unsigned char *limit;
68 {
69 	int sum = 0;
70 
71 	while (buf < limit) {
72 		sum += (buf[0] << 8) + buf[1];
73 		buf += 2;
74 	}
75 	sum += (sum >> 16);
76 	return (sum & 0xffff);
77 }
78 
79 static char *
80 parse_nextstep_label(ondisk, lp, osdep)
81 	struct nextstep_disklabel *ondisk;
82 	struct disklabel *lp;
83 	struct cpu_disklabel *osdep;
84 {
85 	int i, t, nbp;
86 	unsigned short *checksum;
87 
88 	if (ondisk->cd_version == CD_V3) {
89 		checksum = &ondisk->cd_v3_checksum;
90 	} else {
91 		checksum = &ondisk->cd_checksum;
92 	}
93 	if (nextstep_checksum ((unsigned char *)ondisk,
94 			       (unsigned char *)checksum) != *checksum) {
95 		return ("disk label corrupted");
96 	}
97 
98 	osdep->od_version = ondisk->cd_version;
99 	lp->d_magic = lp->d_magic2 = DISKMAGIC;
100 	lp->d_type = DTYPE_SCSI;
101 	lp->d_subtype = 0;
102 	if (sizeof (lp->d_typename) > sizeof (ondisk->cd_name))
103 		lp->d_typename[sizeof (ondisk->cd_name)] = '\0';
104 	memcpy (lp->d_typename, ondisk->cd_name,
105 		min (sizeof (lp->d_typename), sizeof (ondisk->cd_name)));
106 	if (sizeof (lp->d_packname) > sizeof (ondisk->cd_label))
107 		lp->d_packname[sizeof (ondisk->cd_label)] = '\0';
108 	memcpy (lp->d_packname, ondisk->cd_label,
109 		 min (sizeof (lp->d_packname), sizeof (ondisk->cd_label)));
110 	if (lp->d_secsize == 0)
111 		lp->d_secsize = ondisk->cd_secsize;
112 	KASSERT(ondisk->cd_secsize >= lp->d_secsize);
113 	lp->d_nsectors = ondisk->cd_nsectors;
114 	lp->d_ntracks = ondisk->cd_ntracks;
115 	lp->d_ncylinders = ondisk->cd_ncylinders;
116 
117 	lp->d_rpm = ondisk->cd_rpm;
118 	lp->d_flags = ondisk->cd_flags;
119 
120 	lp->d_bbsize = LABELSIZE;
121 	lp->d_sbsize = SBSIZE;
122 
123 	lp->d_npartitions = nbp = 0;
124 	for (i = 0; i < CPUMAXPARTITIONS - 1; i++) {
125 		if (ondisk->cd_partitions[i].cp_size > 0) {
126 			lp->d_partitions[nbp].p_size =
127 				ondisk->cd_partitions[i].cp_size *
128 				(ondisk->cd_secsize / lp->d_secsize);
129 			lp->d_partitions[nbp].p_offset =
130 				(ondisk->cd_front +
131 				 ondisk->cd_partitions[i].cp_offset) *
132 				(ondisk->cd_secsize / lp->d_secsize);
133 			lp->d_partitions[nbp].p_fsize =
134 				ondisk->cd_partitions[i].cp_fsize;
135 #ifndef FSTYPENAMES
136 			lp->d_partitions[nbp].p_fstype =
137 				FS_BSDFFS;
138 #else
139 			for (t = 0; t < FSMAXTYPES; t++) {
140 				if (!strncmp (ondisk->cd_partitions[i].cp_type,
141 					      fstypenames[t], MAXFSTLEN))
142 					break;
143 			}
144 			if (t == FSMAXTYPES)
145 				t = FS_OTHER;
146 			lp->d_partitions[nbp].p_fstype = t;
147 #endif
148 			if (ondisk->cd_partitions[i].cp_fsize)
149 				lp->d_partitions[nbp].p_frag =
150 					ondisk->cd_partitions[i].cp_bsize /
151 					ondisk->cd_partitions[i].cp_fsize;
152 			else
153 				lp->d_partitions[nbp].p_frag = 0;
154 			lp->d_partitions[nbp].p_cpg =
155 				ondisk->cd_partitions[i].cp_cpg;
156 			lp->d_npartitions = nbp + 1;
157 		}
158 		nbp++;
159 		if (nbp == RAW_PART)
160 			nbp++;
161 		if (nbp == MAXPARTITIONS)
162 			break;
163 	}
164 
165 	if (lp->d_npartitions <= RAW_PART)
166 		lp->d_npartitions = RAW_PART + 1;
167 
168 	lp->d_checksum = 0;
169 	lp->d_checksum = dkcksum(lp);
170 
171 	return (NULL);
172 }
173 
174 static int
175 build_nextstep_label(ondisk, lp, osdep)
176 	struct nextstep_disklabel *ondisk;
177 	struct disklabel *lp;
178 	struct cpu_disklabel *osdep;
179 {
180 	int i, t, nbp;
181 	int front_porch = DEFAULTFRONTPORCH;
182 	unsigned short *checksum;
183 
184 	if (osdep->od_version == 0) {
185 		osdep->od_version = CD_V3;
186 
187 		memset (ondisk, 0, sizeof (ondisk));
188 
189 		/* ondisk->cd_label_blkno = 0; */
190 		/* ondisk->cd_size = 0; */
191 		/* ondisk->cd_tag = 0; */
192 		strncpy (ondisk->cd_type, "fixed_rw_scsi", sizeof (ondisk->cd_type));
193 		ondisk->cd_secsize = lp->d_secsize;
194 		/* ondisk->cd_back = 0; */
195 		/* ondisk->cd_ngroups = 0; */
196 		/* ondisk->cd_ag_size = 0; */
197 		/* ondisk->cd_ag_alts = 0; */
198 		/* ondisk->cd_ag_off = 0; */
199 		/* ondisk->kernel */
200 		/* ondisk->hostname */
201 		/* ondisk->rootpartition */
202 		/* ondisk->rwpartition */
203 	}
204 	KASSERT(ondisk->cd_secsize >= lp->d_secsize);
205 
206 	ondisk->cd_version = osdep->od_version;
207 	if (memcmp (ondisk->cd_name, lp->d_typename,
208 		     min (sizeof (lp->d_typename), sizeof (ondisk->cd_name))) &&
209 	    sizeof (ondisk->cd_name) > sizeof (lp->d_typename))
210 		ondisk->cd_name[sizeof (lp->d_typename)] = '\0';
211 	memcpy (ondisk->cd_name, lp->d_typename,
212 		min (sizeof (lp->d_typename), sizeof (ondisk->cd_name)));
213 	if (memcmp (lp->d_packname, ondisk->cd_label,
214 		    min (sizeof (lp->d_packname), sizeof (ondisk->cd_label))) &&
215 	    sizeof (ondisk->cd_label) > sizeof (lp->d_packname))
216 		ondisk->cd_label[sizeof (lp->d_packname)] = '\0';
217 	memcpy (ondisk->cd_label, lp->d_packname,
218 		min (sizeof (lp->d_packname), sizeof (ondisk->cd_label)));
219 
220 	ondisk->cd_nsectors = lp->d_nsectors;
221 	ondisk->cd_ntracks = lp->d_ntracks;
222 	ondisk->cd_ncylinders = lp->d_ncylinders;
223 
224 	ondisk->cd_rpm = lp->d_rpm;
225 	ondisk->cd_flags = lp->d_flags;
226 
227 	/*
228 	 * figure out front porch
229 	 * try to map partitions which were moved
230 	 */
231 	for (nbp = 0; nbp < lp->d_npartitions; nbp++) {
232 		if (nbp != RAW_PART && lp->d_partitions[nbp].p_offset > 0 &&
233 		    lp->d_partitions[nbp].p_offset < front_porch)
234 			front_porch = lp->d_partitions[nbp].p_offset;
235 		for (t = 0; t < CPUMAXPARTITIONS; t++) {
236 			if (t != (nbp > RAW_PART ? nbp-1 : nbp) &&
237 			    (lp->d_partitions[nbp].p_size ==
238 			     ondisk->cd_partitions[t].cp_size *
239 			     (ondisk->cd_secsize / lp->d_secsize)) &&
240 			    (lp->d_partitions[nbp].p_offset ==
241 			     (ondisk->cd_front +
242 			      ondisk->cd_partitions[t].cp_offset) *
243 			     (ondisk->cd_secsize / lp->d_secsize)) &&
244 			    ((lp->d_partitions[nbp].p_fstype == FS_OTHER) ||
245 			     (!strncmp (ondisk->cd_partitions[t].cp_type,
246 					fstypenames[lp->d_partitions[nbp].p_fstype], MAXFSTLEN))))
247 			{
248 				struct cpu_partition tmp;
249 				memcpy (&tmp, &ondisk->cd_partitions[t], sizeof (tmp));
250 				memcpy (&ondisk->cd_partitions[t], &ondisk->cd_partitions[nbp > RAW_PART ? nbp-1 : nbp], sizeof (tmp));
251 				memcpy (&ondisk->cd_partitions[nbp > RAW_PART ? nbp-1 : nbp], &tmp, sizeof (tmp));
252 			}
253 		}
254 	}
255 	front_porch /= (ondisk->cd_secsize / lp->d_secsize);
256 
257 	/*
258 	 * update partitions
259 	 */
260 	nbp = 0;
261 	for (i = 0; i < CPUMAXPARTITIONS; i++) {
262 		struct cpu_partition *p = &ondisk->cd_partitions[i];
263 		if (nbp < lp->d_npartitions && lp->d_partitions[nbp].p_size) {
264 			p->cp_size = lp->d_partitions[nbp].p_size /
265 				(ondisk->cd_secsize / lp->d_secsize);
266 			p->cp_offset = (lp->d_partitions[nbp].p_offset /
267 					(ondisk->cd_secsize / lp->d_secsize)) -
268 				front_porch;
269 			p->cp_bsize = lp->d_partitions[nbp].p_frag
270 				* lp->d_partitions[nbp].p_fsize;
271 			p->cp_fsize = lp->d_partitions[nbp].p_fsize;
272 			if (lp->d_partitions[nbp].p_fstype != FS_OTHER) {
273 				memset (p->cp_type, 0, MAXFSTLEN);
274 				strncpy (p->cp_type,
275 					 fstypenames[lp->d_partitions[nbp].p_fstype], MAXFSTLEN);
276 			}
277 			if (p->cp_density < 0)
278 				p->cp_density = 4096; /* set some default */
279 			if (p->cp_minfree < 0)
280 				p->cp_minfree = 5; /* set some default */
281 			p->cp_cpg = lp->d_partitions[nbp].p_cpg;
282 		} else {
283 			memset (p, 0, sizeof(p));
284 			p->cp_size = -1;
285 			p->cp_offset = -1;
286 			p->cp_bsize = -1;
287 			p->cp_fsize = -1;
288 			p->cp_density = -1;
289 			p->cp_minfree = -1;
290 		}
291 		nbp++;
292 		if (nbp == RAW_PART)
293 			nbp++;
294 	}
295 
296 	ondisk->cd_front = front_porch;
297 	ondisk->cd_boot_blkno[0] = DEFAULTBOOT0_1 /
298 				(ondisk->cd_secsize / lp->d_secsize);
299 	ondisk->cd_boot_blkno[1] = DEFAULTBOOT0_2 /
300 				(ondisk->cd_secsize / lp->d_secsize);
301 
302 	if (ondisk->cd_version == CD_V3) {
303 		checksum = &ondisk->cd_v3_checksum;
304 	} else {
305 		checksum = &ondisk->cd_checksum;
306 	}
307 	*checksum = nextstep_checksum ((unsigned char *)ondisk,
308 				       (unsigned char *)checksum);
309 
310 	return 0;
311 }
312 
313 /*
314  * Attempt to read a disk label from a device using the indicated strategy
315  * routine.  The label must be partly set up before this: secpercyl and
316  * anything required in the strategy routine (e.g., sector size) must be
317  * filled in before calling us.  Returns null on success and an error
318  * string on failure.
319  */
320 char *
321 readdisklabel(dev, strat, lp, osdep)
322 	dev_t dev;
323 	void (*strat) __P((struct buf *));
324 	struct disklabel *lp;
325 	struct cpu_disklabel *osdep;
326 {
327 	struct buf *bp;
328 	struct disklabel *dlp;
329 	char *msg = NULL;
330 	int i;
331 
332 	/* minimal requirements for archtypal disk label */
333 	if (lp->d_secsize == 0)
334 		lp->d_secsize = DEV_BSIZE;
335 	if (lp->d_secperunit == 0)
336 		lp->d_secperunit = 0x1fffffff;
337 	lp->d_npartitions = RAW_PART + 1;
338 	for (i = 0; i < RAW_PART; i++) {
339 		lp->d_partitions[i].p_size = 0;
340 		lp->d_partitions[i].p_offset = 0;
341 	}
342 	if (lp->d_partitions[i].p_size == 0)
343 		lp->d_partitions[i].p_size = 0x1fffffff;
344 	lp->d_partitions[i].p_offset = 0;
345 
346 	bp = geteblk(LABELSIZE);
347 	bp->b_dev = dev;
348 	bp->b_blkno = LABELSECTOR;
349 	bp->b_bcount = LABELSIZE;
350 	bp->b_flags |= B_READ;
351 	bp->b_cylinder = LABELSECTOR / lp->d_secpercyl;
352 	(*strat)(bp);
353 
354 	if (osdep)
355 		osdep->od_version = 0;
356 
357 	if (biowait(bp))
358 		msg = "I/O error";
359 	else if (IS_DISKLABEL ((struct nextstep_disklabel *)bp->b_data))
360 		msg = parse_nextstep_label
361 			((struct nextstep_disklabel *)bp->b_data, lp, osdep);
362 	else {
363 		if (osdep &&
364 		    ((struct disklabel *)bp->b_data)->d_magic == DISKMAGIC)
365 			osdep->od_version = DISKMAGIC;
366 		for (dlp = (struct disklabel *)bp->b_data;
367 		     dlp <= (struct disklabel *)((char *)bp->b_data +
368 						 DEV_BSIZE - sizeof(*dlp));
369 		     dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
370 			if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
371 				if (msg == NULL)
372 					msg = "no disk label";
373 			} else if (dlp->d_npartitions > MAXPARTITIONS ||
374 				   dkcksum(dlp) != 0)
375 				msg = "disk label corrupted";
376 			else {
377 				*lp = *dlp;
378 				msg = NULL;
379 				if (osdep)
380 					osdep->od_version = DISKMAGIC;
381 				break;
382 			}
383 		}
384 	}
385 	brelse(bp);
386 	return (msg);
387 }
388 
389 /*
390  * Check new disk label for sensibility before setting it.
391  */
392 int
393 setdisklabel(olp, nlp, openmask, osdep)
394 	struct disklabel *olp, *nlp;
395 	u_long openmask;
396 	struct cpu_disklabel *osdep;
397 {
398 	int i;
399 	struct partition *opp, *npp;
400 
401 	if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
402 	    dkcksum(nlp) != 0)
403 		return (EINVAL);
404 	while ((i = ffs(openmask)) != 0) {
405 		i--;
406 		openmask &= ~(1 << i);
407 		if (nlp->d_npartitions <= i)
408 			return (EBUSY);
409 		opp = &olp->d_partitions[i];
410 		npp = &nlp->d_partitions[i];
411 		if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
412 			return (EBUSY);
413 		/*
414 		 * Copy internally-set partition information
415 		 * if new label doesn't include it.		XXX
416 		 */
417 		if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
418 			npp->p_fstype = opp->p_fstype;
419 			npp->p_fsize = opp->p_fsize;
420 			npp->p_frag = opp->p_frag;
421 			npp->p_cpg = opp->p_cpg;
422 		}
423 	}
424 	nlp->d_checksum = 0;
425 	nlp->d_checksum = dkcksum(nlp);
426 	*olp = *nlp;
427 	return (0);
428 }
429 
430 /*
431  * Write disk label back to device after modification.
432  */
433 int
434 writedisklabel(dev, strat, lp, osdep)
435 	dev_t dev;
436 	void (*strat) __P((struct buf *));
437 	struct disklabel *lp;
438 	struct cpu_disklabel *osdep;
439 {
440 	struct buf *bp;
441 	struct disklabel *dlp;
442 	int labelpart;
443 	int error = 0;
444 
445 	labelpart = DISKPART(dev);
446 	if (lp->d_partitions[labelpart].p_offset != 0) {
447 		if (lp->d_partitions[0].p_offset != 0)
448 			return (EXDEV);			/* not quite right */
449 		labelpart = 0;
450 	}
451 	if (osdep->od_version != DISKMAGIC) {
452 		bp = geteblk(LABELSIZE);
453 		bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), labelpart);
454 		bp->b_blkno = LABELSECTOR;
455 		bp->b_bcount = LABELSIZE;
456 		bp->b_flags |= B_READ;
457 		bp->b_cylinder = LABELSECTOR / lp->d_secpercyl;
458 		(*strat)(bp);
459 		error = biowait(bp);
460 		if (error)
461 			goto done;
462 		error = build_nextstep_label
463 			((struct nextstep_disklabel *)bp->b_data, lp, osdep);
464 		if (error)
465 			goto done;
466 		bp->b_flags &= ~(B_READ|B_DONE);
467 		bp->b_flags |= B_WRITE;
468 		(*strat)(bp);
469 		error = biowait(bp);
470 	} else {
471 		bp = geteblk((int)lp->d_secsize);
472 		bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), labelpart);
473 		bp->b_blkno = LABELSECTOR;
474 		bp->b_bcount = lp->d_secsize;
475 		bp->b_flags |= B_READ;
476 		(*strat)(bp);
477 		if ((error = biowait(bp)))
478 			goto done;
479 		for (dlp = (struct disklabel *)bp->b_data;
480 		     dlp <= (struct disklabel *)
481 			     ((char *)bp->b_data + lp->d_secsize - sizeof(*dlp));
482 		     dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
483 			if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
484 			    dkcksum(dlp) == 0) {
485 				*dlp = *lp;
486 				bp->b_flags &= ~(B_READ|B_DONE);
487 				bp->b_flags |= B_WRITE;
488 				(*strat)(bp);
489 				error = biowait(bp);
490 				goto done;
491 			}
492 		}
493 		error = ESRCH;
494 	}
495 done:
496 	brelse(bp);
497 	return (error);
498 }
499 
500 /*
501  * Determine the size of the transfer, and make sure it is
502  * within the boundaries of the partition. Adjust transfer
503  * if needed, and signal errors or early completion.
504  */
505 int
506 bounds_check_with_label(bp, lp, wlabel)
507 	struct buf *bp;
508 	struct disklabel *lp;
509 	int wlabel;
510 {
511 	struct partition *p = &lp->d_partitions[DISKPART(bp->b_dev)];
512 	int labelsect = lp->d_partitions[0].p_offset;
513 	int maxsz = p->p_size;
514 	int sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
515 
516 	/* Overwriting disk label? */
517 	if (bp->b_blkno + p->p_offset <= LABELSECTOR + labelsect &&
518 	    (bp->b_flags & B_READ) == 0 && !wlabel) {
519 		bp->b_error = EROFS;
520 		goto bad;
521 	}
522 
523 	/* beyond partition? */
524 	if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
525 		if (bp->b_blkno == maxsz) {
526 			/* If exactly at end of disk, return EOF. */
527 			bp->b_resid = bp->b_bcount;
528 			return (0);
529 		}
530 		/* ...or truncate if part of it fits */
531 		sz = maxsz - bp->b_blkno;
532 		if (sz <= 0) {
533 			bp->b_error = EINVAL;
534 			goto bad;
535 		}
536 		bp->b_bcount = sz << DEV_BSHIFT;
537 	}
538 
539 	/* calculate cylinder for disksort to order transfers with */
540 	bp->b_resid = (bp->b_blkno + p->p_offset) / lp->d_secpercyl;
541 	return (1);
542 
543  bad:
544 	bp->b_flags |= B_ERROR;
545 	return (-1);
546 }
547