xref: /netbsd-src/sys/arch/next68k/next68k/disksubr.c (revision e2d073377d21df6c8398f0bd0d121c9f0a6ddab7)
1 /*	$NetBSD: disksubr.c,v 1.32 2023/02/04 02:08:03 tsutsui 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. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	@(#)ufs_disksubr.c	8.5 (Berkeley) 1/21/94
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.32 2023/02/04 02:08:03 tsutsui Exp $");
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/buf.h>
45 #define FSTYPENAMES
46 #include <sys/disklabel.h>
47 #include <sys/syslog.h>
48 
49 #include <sys/disk.h>
50 
51 #include <ufs/ufs/dinode.h>             /* XXX for fs.h */
52 #include <ufs/ffs/fs.h>                 /* XXX for SBLOCKSIZE */
53 
54 #define	b_cylinder	b_resid
55 
56 static uint16_t nextstep_checksum(unsigned char *, unsigned char *);
57 static const char *parse_nextstep_label(struct next68k_disklabel *,
58     struct disklabel *, struct cpu_disklabel *);
59 static int build_nextstep_label(struct next68k_disklabel *, struct disklabel *);
60 
61 static uint16_t
nextstep_checksum(unsigned char * buf,unsigned char * limit)62 nextstep_checksum(unsigned char *buf, unsigned char *limit)
63 {
64 	int sum = 0;
65 
66 	while (buf < limit) {
67 		sum += (buf[0] << 8) + buf[1];
68 		buf += 2;
69 	}
70 	sum += (sum >> 16);
71 	return sum & 0xffff;
72 }
73 
74 static const char *
parse_nextstep_label(struct next68k_disklabel * ondisk,struct disklabel * lp,struct cpu_disklabel * osdep)75 parse_nextstep_label(struct next68k_disklabel *ondisk, struct disklabel *lp,
76     struct cpu_disklabel *osdep)
77 {
78 	int i, t, nbp;
79 	uint16_t *checksum;
80 
81 	if (ondisk->cd_version == NEXT68K_LABEL_CD_V3) {
82 		checksum = &ondisk->NEXT68K_LABEL_cd_v3_checksum;
83 	} else {
84 		checksum = &ondisk->NEXT68K_LABEL_cd_checksum;
85 	}
86 	if (nextstep_checksum((uint8_t *)ondisk, (uint8_t *)checksum) !=
87 	    *checksum) {
88 		return "disk label corrupted";
89 	}
90 
91 	osdep->od_version = ondisk->cd_version;
92 	lp->d_magic = lp->d_magic2 = DISKMAGIC;
93 	lp->d_type = DKTYPE_SCSI;
94 	lp->d_subtype = 0;
95 	if (sizeof(lp->d_typename) > sizeof(ondisk->cd_name))
96 		lp->d_typename[sizeof (ondisk->cd_name)] = '\0';
97 	memcpy(lp->d_typename, ondisk->cd_name,
98 	    uimin(sizeof (lp->d_typename), sizeof(ondisk->cd_name)));
99 	if (sizeof(lp->d_packname) > sizeof(ondisk->cd_label))
100 		lp->d_packname[sizeof (ondisk->cd_label)] = '\0';
101 	memcpy(lp->d_packname, ondisk->cd_label,
102 	    uimin(sizeof(lp->d_packname), sizeof(ondisk->cd_label)));
103 	if (lp->d_secsize == 0)
104 		lp->d_secsize = ondisk->cd_secsize;
105 	KASSERT(ondisk->cd_secsize >= lp->d_secsize);
106 	lp->d_nsectors = ondisk->cd_nsectors;
107 	lp->d_ntracks = ondisk->cd_ntracks;
108 	lp->d_ncylinders = ondisk->cd_ncylinders;
109 
110 	lp->d_rpm = ondisk->cd_rpm;
111 	lp->d_flags = ondisk->cd_flags;
112 
113 	lp->d_bbsize = NEXT68K_LABEL_SIZE;
114 	lp->d_sbsize = SBLOCKSIZE;
115 
116 	lp->d_npartitions = nbp = 0;
117 	for (i = 0; i < NEXT68K_LABEL_MAXPARTITIONS - 1; i++) {
118 		if (ondisk->cd_partitions[i].cp_size > 0) {
119 			lp->d_partitions[nbp].p_size =
120 			    ondisk->cd_partitions[i].cp_size *
121 			    (ondisk->cd_secsize / lp->d_secsize);
122 			lp->d_partitions[nbp].p_offset =
123 			    (ondisk->cd_front +
124 			     ondisk->cd_partitions[i].cp_offset) *
125 			     (ondisk->cd_secsize / lp->d_secsize);
126 			lp->d_partitions[nbp].p_fsize =
127 			    ondisk->cd_partitions[i].cp_fsize;
128 #ifndef FSTYPENAMES
129 			lp->d_partitions[nbp].p_fstype = FS_BSDFFS;
130 #else
131 			for (t = 0; t < FSMAXTYPES; t++) {
132 				if (strncmp(ondisk->cd_partitions[i].cp_type,
133 				    fstypenames[t], NEXT68K_LABEL_MAXFSTLEN)
134 				    == 0)
135 					break;
136 			}
137 			if (t == FSMAXTYPES)
138 				t = FS_OTHER;
139 			lp->d_partitions[nbp].p_fstype = t;
140 #endif
141 			if (ondisk->cd_partitions[i].cp_fsize)
142 				lp->d_partitions[nbp].p_frag =
143 				    ondisk->cd_partitions[i].cp_bsize /
144 				    ondisk->cd_partitions[i].cp_fsize;
145 			else
146 				lp->d_partitions[nbp].p_frag = 0;
147 			lp->d_partitions[nbp].p_cpg =
148 				ondisk->cd_partitions[i].cp_cpg;
149 			lp->d_npartitions = nbp + 1;
150 		}
151 		nbp++;
152 		if (nbp == RAW_PART)
153 			nbp++;
154 		if (nbp == MAXPARTITIONS)
155 			break;
156 	}
157 
158 	if (lp->d_npartitions <= RAW_PART)
159 		lp->d_npartitions = RAW_PART + 1;
160 
161 	lp->d_checksum = 0;
162 	lp->d_checksum = dkcksum(lp);
163 
164 	return NULL;
165 }
166 
167 static int
build_nextstep_label(struct next68k_disklabel * ondisk,struct disklabel * lp)168 build_nextstep_label(struct next68k_disklabel *ondisk, struct disklabel *lp)
169 {
170 	int i, t, nbp;
171 	int front_porch = NEXT68K_LABEL_DEFAULTFRONTPORCH;
172 	uint16_t *checksum;
173 
174 	memset(ondisk, 0, sizeof(*ondisk));
175 
176 	ondisk->cd_version = NEXT68K_LABEL_CD_V3;
177 	/* ondisk->cd_label_blkno = 0; */
178 	/* ondisk->cd_size = 0; */
179 	/* ondisk->cd_tag = 0; */
180 	strncpy(ondisk->cd_type, "fixed_rw_scsi", sizeof(ondisk->cd_type));
181 	ondisk->cd_secsize = lp->d_secsize;
182 	/* ondisk->cd_back = 0; */
183 	/* ondisk->cd_ngroups = 0; */
184 	/* ondisk->cd_ag_size = 0; */
185 	/* ondisk->cd_ag_alts = 0; */
186 	/* ondisk->cd_ag_off = 0; */
187 	/* ondisk->kernel */
188 	/* ondisk->hostname */
189 	/* ondisk->rootpartition */
190 	/* ondisk->rwpartition */
191 	KASSERT(ondisk->cd_secsize >= lp->d_secsize);
192 
193 	if (memcmp(ondisk->cd_name, lp->d_typename,
194 	    uimin(sizeof(lp->d_typename), sizeof(ondisk->cd_name))) &&
195 	    sizeof (ondisk->cd_name) > sizeof (lp->d_typename))
196 		ondisk->cd_name[sizeof(lp->d_typename)] = '\0';
197 	memcpy(ondisk->cd_name, lp->d_typename,
198 	    uimin(sizeof(lp->d_typename), sizeof(ondisk->cd_name)));
199 	if (memcmp (lp->d_packname, ondisk->cd_label,
200 	    uimin(sizeof(lp->d_packname), sizeof(ondisk->cd_label))) &&
201 	    sizeof(ondisk->cd_label) > sizeof(lp->d_packname))
202 		ondisk->cd_label[sizeof(lp->d_packname)] = '\0';
203 	memcpy(ondisk->cd_label, lp->d_packname,
204 	    uimin(sizeof(lp->d_packname), sizeof(ondisk->cd_label)));
205 
206 	ondisk->cd_nsectors = lp->d_nsectors;
207 	ondisk->cd_ntracks = lp->d_ntracks;
208 	ondisk->cd_ncylinders = lp->d_ncylinders;
209 
210 	ondisk->cd_rpm = lp->d_rpm;
211 	ondisk->cd_flags = lp->d_flags;
212 
213 	/*
214 	 * figure out front porch
215 	 * try to map partitions which were moved
216 	 */
217 	for (nbp = 0; nbp < lp->d_npartitions; nbp++) {
218 		if (nbp != RAW_PART && lp->d_partitions[nbp].p_offset > 0 &&
219 		    lp->d_partitions[nbp].p_offset < front_porch)
220 			front_porch = lp->d_partitions[nbp].p_offset;
221 		for (t = 0; t < NEXT68K_LABEL_MAXPARTITIONS; t++) {
222 			if (t != (nbp > RAW_PART ? nbp - 1 : nbp) &&
223 			    (lp->d_partitions[nbp].p_size ==
224 			     ondisk->cd_partitions[t].cp_size *
225 			     (ondisk->cd_secsize / lp->d_secsize)) &&
226 			    (lp->d_partitions[nbp].p_offset ==
227 			     (ondisk->cd_front +
228 			      ondisk->cd_partitions[t].cp_offset) *
229 			     (ondisk->cd_secsize / lp->d_secsize)) &&
230 			    ((lp->d_partitions[nbp].p_fstype == FS_OTHER) ||
231 			     (!strncmp (ondisk->cd_partitions[t].cp_type,
232 				 fstypenames[lp->d_partitions[nbp].p_fstype],
233 				 NEXT68K_LABEL_MAXFSTLEN)))) {
234 				struct next68k_partition tmp;
235 				memcpy(&tmp, &ondisk->cd_partitions[t],
236 				    sizeof(tmp));
237 				memcpy(&ondisk->cd_partitions[t],
238 				    &ondisk->cd_partitions[nbp > RAW_PART ?
239 				    nbp - 1 : nbp],
240 				    sizeof (tmp));
241 				memcpy(&ondisk->cd_partitions[nbp > RAW_PART ?
242 				    nbp - 1 : nbp],
243 				    &tmp, sizeof (tmp));
244 			}
245 		}
246 	}
247 	front_porch /= (ondisk->cd_secsize / lp->d_secsize);
248 
249 	/*
250 	 * update partitions
251 	 */
252 	nbp = 0;
253 	for (i = 0; i < NEXT68K_LABEL_MAXPARTITIONS; i++) {
254 		struct next68k_partition *p = &ondisk->cd_partitions[i];
255 		if (nbp < lp->d_npartitions && lp->d_partitions[nbp].p_size) {
256 			p->cp_size = lp->d_partitions[nbp].p_size /
257 			    (ondisk->cd_secsize / lp->d_secsize);
258 			p->cp_offset = (lp->d_partitions[nbp].p_offset /
259 			    (ondisk->cd_secsize / lp->d_secsize)) -
260 			    front_porch;
261 			p->cp_bsize = lp->d_partitions[nbp].p_frag
262 			    * lp->d_partitions[nbp].p_fsize;
263 			p->cp_fsize = lp->d_partitions[nbp].p_fsize;
264 			if (lp->d_partitions[nbp].p_fstype != FS_OTHER) {
265 				memset(p->cp_type, 0, NEXT68K_LABEL_MAXFSTLEN);
266 				strncpy(p->cp_type,
267 				    fstypenames[lp->d_partitions[nbp].p_fstype],
268 				    NEXT68K_LABEL_MAXFSTLEN);
269 			}
270 			if (p->cp_density < 0)
271 				p->cp_density = 4096; /* set some default */
272 			if (p->cp_minfree < 0)
273 				p->cp_minfree = 5; /* set some default */
274 			p->cp_cpg = lp->d_partitions[nbp].p_cpg;
275 		} else {
276 			memset(p, 0, sizeof(*p));
277 			p->cp_size = -1;
278 			p->cp_offset = -1;
279 			p->cp_bsize = -1;
280 			p->cp_fsize = -1;
281 			p->cp_density = -1;
282 			p->cp_minfree = -1;
283 		}
284 		nbp++;
285 		if (nbp == RAW_PART)
286 			nbp++;
287 	}
288 
289 	ondisk->cd_front = front_porch;
290 	ondisk->cd_boot_blkno[0] = NEXT68K_LABEL_DEFAULTBOOT0_1 /
291 	    (ondisk->cd_secsize / lp->d_secsize);
292 	ondisk->cd_boot_blkno[1] = NEXT68K_LABEL_DEFAULTBOOT0_2 /
293 	    (ondisk->cd_secsize / lp->d_secsize);
294 
295 	if (ondisk->cd_version == NEXT68K_LABEL_CD_V3) {
296 		checksum = &ondisk->NEXT68K_LABEL_cd_v3_checksum;
297 	} else {
298 		checksum = &ondisk->NEXT68K_LABEL_cd_checksum;
299 	}
300 	*checksum = nextstep_checksum((uint8_t *)ondisk, (uint8_t *)checksum);
301 
302 	return 0;
303 }
304 
305 /*
306  * Attempt to read a disk label from a device using the indicated strategy
307  * routine.  The label must be partly set up before this: secpercyl and
308  * anything required in the strategy routine (e.g., sector size) must be
309  * filled in before calling us.  Returns null on success and an error
310  * string on failure.
311  */
312 const char *
readdisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)313 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
314     struct cpu_disklabel *osdep)
315 {
316 	struct buf *bp;
317 	struct disklabel *dlp;
318 	const char *msg = NULL;
319 	int i;
320 
321 	/* minimal requirements for archtypal disk label */
322 	if (lp->d_secsize == 0)
323 		lp->d_secsize = DEV_BSIZE;
324 	if (lp->d_secperunit == 0)
325 		lp->d_secperunit = 0x1fffffff;
326 	lp->d_npartitions = RAW_PART + 1;
327 	for (i = 0; i < RAW_PART; i++) {
328 		lp->d_partitions[i].p_size = 0;
329 		lp->d_partitions[i].p_offset = 0;
330 	}
331 	if (lp->d_partitions[i].p_size == 0)
332 		lp->d_partitions[i].p_size = 0x1fffffff;
333 	lp->d_partitions[i].p_offset = 0;
334 
335 	bp = geteblk(NEXT68K_LABEL_SIZE);
336 	bp->b_dev = dev;
337 	bp->b_blkno = NEXT68K_LABEL_SECTOR;
338 	bp->b_bcount = NEXT68K_LABEL_SIZE;
339 	bp->b_flags |= B_READ;
340 	bp->b_cylinder = NEXT68K_LABEL_SECTOR / lp->d_secpercyl;
341 	(*strat)(bp);
342 
343 	if (osdep)
344 		osdep->od_version = 0;
345 
346 	if (biowait(bp)) {
347 		brelse(bp, 0);
348 		return("I/O error");
349 	}
350 	dlp = (struct disklabel *)
351 	    ((char *)bp->b_data + LABELSECTOR * lp->d_secsize + LABELOFFSET);
352 	if (dlp->d_magic == DISKMAGIC || dlp->d_magic2 == DISKMAGIC) {
353 		/* got a NetBSD disklabel */
354 		if (osdep)
355 			osdep->od_version = DISKMAGIC;
356 		if (dlp->d_npartitions > MAXPARTITIONS ||
357 			   dkcksum(dlp) != 0)
358 			msg = "disk label corrupted";
359 		else {
360 			*lp = *dlp;
361 			msg = NULL;
362 		}
363 		brelse(bp, 0);
364 		return msg;
365 	}
366 	if (IS_DISKLABEL((struct next68k_disklabel *)bp->b_data)) {
367 		/* got a NeXT disklabel */
368 		msg = parse_nextstep_label(
369 		    (struct next68k_disklabel *)bp->b_data, lp, osdep);
370 		brelse(bp, 0);
371 		return msg;
372 	}
373 	/*
374 	 * no disklabel at the usual places. Try to locate a NetBSD disklabel
375 	 * in the first sector. This ensure compatibility with others
376 	 * big-endian systems, and with next68k when LABELSECTOR was 0.
377 	 */
378 	msg = "no disk label";
379 	for (dlp = (struct disklabel *)bp->b_data;
380 	     dlp <= (struct disklabel *)((char *)bp->b_data +
381 	     DEV_BSIZE - sizeof(*dlp));
382 	     dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
383 		if (dlp->d_magic == DISKMAGIC || dlp->d_magic2 == DISKMAGIC) {
384 			if (dlp->d_npartitions > MAXPARTITIONS ||
385 			   dkcksum(dlp) != 0)
386 				msg = "disk label corrupted";
387 			else {
388 				*lp = *dlp;
389 				msg = NULL;
390 				if (osdep)
391 					osdep->od_version = DISKMAGIC;
392 				break;
393 			}
394 		}
395 	}
396 	brelse(bp, 0);
397 	return msg;
398 }
399 
400 /*
401  * Write disk label back to device after modification.
402  */
403 int
writedisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)404 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
405     struct cpu_disklabel *osdep)
406 {
407 	struct buf *bp;
408 #if 0
409 	struct disklabel *dlp;
410 #endif
411 	int labelpart;
412 	int error = 0;
413 
414 	labelpart = DISKPART(dev);
415 	if (lp->d_partitions[labelpart].p_offset != 0) {
416 		if (lp->d_partitions[0].p_offset != 0)
417 			return EXDEV;			/* not quite right */
418 		labelpart = 0;
419 	}
420 	/*
421 	 * We always write a NeXT v3 disklabel, and a NetBSD disklabel in
422 	 * the last sector of the NeXT label area.
423 	 */
424 
425 	bp = geteblk(NEXT68K_LABEL_SIZE);
426 	bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), labelpart);
427 	bp->b_blkno = NEXT68K_LABEL_SECTOR;
428 	bp->b_bcount = NEXT68K_LABEL_SIZE;
429 	bp->b_flags |= B_WRITE;
430 	bp->b_cylinder = NEXT68K_LABEL_SECTOR / lp->d_secpercyl;
431 	error =
432 	    build_nextstep_label((struct next68k_disklabel *)bp->b_data, lp);
433 	if (error)
434 		goto done;
435 #if 0
436 	dlp = (struct disklabel *)
437 	    ((char *)bp->b_data + LABELSECTOR * lp->d_secsize + LABELOFFSET);
438 	*dlp = *lp;
439 #endif
440 	(*strat)(bp);
441 	error = biowait(bp);
442  done:
443 	brelse(bp, 0);
444 	return error;
445 }
446