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