xref: /netbsd/sys/arch/mvme68k/mvme68k/disksubr.c (revision 6550d01e)
1 /*	$NetBSD: disksubr.c,v 1.35 2009/10/23 03:28:09 snj Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Dale Rahn.
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. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.35 2009/10/23 03:28:09 snj Exp $");
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/buf.h>
36 #include <sys/device.h>
37 #define FSTYPENAMES
38 #include <sys/disklabel.h>
39 #include <sys/disk.h>
40 
41 #include <dev/scsipi/scsi_all.h>
42 #include <dev/scsipi/scsipi_all.h>
43 #include <dev/scsipi/scsiconf.h>
44 
45 #include <machine/autoconf.h>
46 
47 #ifdef DEBUG
48 int disksubr_debug = 0;
49 #endif
50 
51 static void bsdtocpulabel(struct disklabel *lp, struct cpu_disklabel *clp);
52 static void cputobsdlabel(struct disklabel *lp, struct cpu_disklabel *clp);
53 
54 #ifdef DEBUG
55 static void printlp(struct disklabel *lp, const char *str);
56 static void printclp(struct cpu_disklabel *clp, const char *str);
57 #endif
58 
59 
60 /*
61  * Attempt to read a disk label from a device
62  * using the indicated strategy routine.
63  * The label must be partly set up before this:
64  * secpercyl and anything required in the strategy routine
65  * (e.g., sector size) must be filled in before calling us.
66  * Returns null on success and an error string on failure.
67  */
68 const char *
69 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
70     struct cpu_disklabel *clp)
71 {
72 	struct buf *bp;
73 	const char *msg = NULL;
74 
75 	/* obtain buffer to probe drive with */
76 	bp = geteblk((int)lp->d_secsize);
77 
78 	/* request no partition relocation by driver on I/O operations */
79 	bp->b_dev = dev;
80 	bp->b_blkno = 0; /* contained in block 0 */
81 	bp->b_bcount = lp->d_secsize;
82 	bp->b_flags |= B_READ;
83 	bp->b_cylinder = 0; /* contained in block 0 */
84 	(*strat)(bp);
85 
86 	if (biowait(bp)) {
87 		msg = "cpu_disklabel read error\n";
88 	} else {
89 		memcpy(clp, bp->b_data, sizeof (struct cpu_disklabel));
90 	}
91 
92 	brelse(bp, 0);
93 
94 	if (msg || clp->magic1 != DISKMAGIC || clp->magic2 != DISKMAGIC) {
95 		return msg;
96 	}
97 
98 	cputobsdlabel(lp, clp);
99 #ifdef DEBUG
100 	if(disksubr_debug > 0) {
101 		printlp(lp, "readdisklabel: bsd label");
102 		printclp(clp, "readdisklabel: cpu label");
103 	}
104 #endif
105 	return msg;
106 }
107 
108 /*
109  * Check new disk label for sensibility
110  * before setting it.
111  */
112 int
113 setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask,
114     struct cpu_disklabel *clp)
115 {
116 	int i;
117 	struct partition *opp, *npp;
118 
119 #ifdef DEBUG
120 	if (disksubr_debug > 0) {
121 		printlp(nlp, "setdisklabel: new disklabel");
122 		printlp(olp, "setdisklabel: old disklabel");
123 		printclp(clp, "setdisklabel:cpu disklabel");
124 	}
125 #endif
126 
127 
128 	/* sanity clause */
129 	if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 ||
130 	    (nlp->d_secsize % DEV_BSIZE) != 0)
131 		return EINVAL;
132 
133 	/* special case to allow disklabel to be invalidated */
134 	if (nlp->d_magic == 0xffffffff) {
135 		*olp = *nlp;
136 		return 0;
137 	}
138 
139 	if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
140 	    dkcksum(nlp) != 0)
141 		return EINVAL;
142 
143 	while ((i = ffs(openmask)) != 0) {
144 		i--;
145 		openmask &= ~(1 << i);
146 		if (nlp->d_npartitions <= i)
147 			return (EBUSY);
148 		opp = &olp->d_partitions[i];
149 		npp = &nlp->d_partitions[i];
150 		if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
151 			return EBUSY;
152 		/*
153 		 * Copy internally-set partition information
154 		 * if new label doesn't include it.		XXX
155 		 */
156 		if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
157 			npp->p_fstype = opp->p_fstype;
158 			npp->p_fsize = opp->p_fsize;
159 			npp->p_frag = opp->p_frag;
160 			npp->p_cpg = opp->p_cpg;
161 		}
162 	}
163 
164  	nlp->d_checksum = 0;
165  	nlp->d_checksum = dkcksum(nlp);
166 	*olp = *nlp;
167 #ifdef DEBUG
168 	if(disksubr_debug > 0) {
169 		printlp(olp, "setdisklabel: old->new disklabel");
170 	}
171 #endif
172 	return 0;
173 }
174 
175 /*
176  * Write disk label back to device after modification.
177  */
178 int
179 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
180     struct cpu_disklabel *clp)
181 {
182 	struct buf *bp;
183 	int error;
184 
185 #ifdef DEBUG
186 	if(disksubr_debug > 0) {
187 		printlp(lp, "writedisklabel: bsd label");
188 	}
189 #endif
190 
191 	/*
192 	 * obtain buffer to read initial cpu_disklabel, for bootloader size :-)
193 	 */
194 	bp = geteblk((int)lp->d_secsize);
195 
196 	/* request no partition relocation by driver on I/O operations */
197 	bp->b_dev = dev;
198 	bp->b_blkno = 0; /* contained in block 0 */
199 	bp->b_bcount = lp->d_secsize;
200 	bp->b_flags |= B_READ;
201 	bp->b_cylinder = 0; /* contained in block 0 */
202 	(*strat)(bp);
203 
204 	if ( (error = biowait(bp)) != 0 ) {
205 		/* nothing */
206 	} else {
207 		memcpy(clp, bp->b_data, sizeof(struct cpu_disklabel));
208 	}
209 
210 	brelse(bp, 0);
211 
212 	if (error) {
213 		return error;
214 	}
215 
216 	bsdtocpulabel(lp, clp);
217 
218 #ifdef DEBUG
219 	if (disksubr_debug > 0) {
220 		printclp(clp, "writedisklabel: cpu label");
221 	}
222 #endif
223 
224 	if (lp->d_magic == DISKMAGIC && lp->d_magic2 == DISKMAGIC &&
225 	    dkcksum(lp) == 0) {
226 		/* obtain buffer to scrozz drive with */
227 		bp = geteblk((int)lp->d_secsize);
228 
229 		memcpy(bp->b_data, clp, sizeof(struct cpu_disklabel));
230 
231 		/*
232 		 * request no partition relocation by driver on I/O operations
233 		 */
234 		bp->b_dev = dev;
235 		bp->b_blkno = 0; /* contained in block 0 */
236 		bp->b_bcount = lp->d_secsize;
237 		bp->b_flags |= B_WRITE;
238 		bp->b_cylinder = 0; /* contained in block 0 */
239 		(*strat)(bp);
240 
241 		error = biowait(bp);
242 
243 		brelse(bp, 0);
244 	}
245 	return error;
246 }
247 
248 static void
249 bsdtocpulabel(struct disklabel *lp, struct cpu_disklabel *clp)
250 {
251 	int i;
252 
253 	clp->magic1 = lp->d_magic;
254 	clp->type = lp->d_type;
255 	clp->subtype = lp->d_subtype;
256 	strncpy(clp->vid_vd, lp->d_typename, 16);
257 	strncpy(clp->packname, lp->d_packname, 16);
258 	clp->cfg_psm = lp->d_secsize;
259 	clp->cfg_spt = lp->d_nsectors;
260 	clp->cfg_trk = lp->d_ncylinders;	/* trk is really num of cyl! */
261 	clp->cfg_hds = lp->d_ntracks;
262 
263 	clp->secpercyl = lp->d_secpercyl;
264 	clp->secperunit = lp->d_secperunit;
265 	clp->sparespertrack = lp->d_sparespertrack;
266 	clp->sparespercyl = lp->d_sparespercyl;
267 	clp->acylinders = lp->d_acylinders;
268 	clp->rpm = lp->d_rpm;
269 
270 	clp->cfg_ilv = lp->d_interleave;
271 	clp->cfg_sof = lp->d_trackskew;
272 	clp->cylskew = lp->d_cylskew;
273 	clp->headswitch = lp->d_headswitch;
274 
275 	/* this silly table is for winchester drives */
276 	if (lp->d_trkseek < 6) {
277 		clp->cfg_ssr = 0;
278 	} else if (lp->d_trkseek < 10) {
279 		clp->cfg_ssr = 1;
280 	} else if (lp->d_trkseek < 15) {
281 		clp->cfg_ssr = 2;
282 	} else if (lp->d_trkseek < 20) {
283 		clp->cfg_ssr = 3;
284 	} else {
285 		clp->cfg_ssr = 4;
286 	}
287 
288 	clp->flags = lp->d_flags;
289 	for (i = 0; i < NDDATA; i++)
290 		clp->drivedata[i] = lp->d_drivedata[i];
291 	for (i = 0; i < NSPARE; i++)
292 		clp->spare[i] = lp->d_spare[i];
293 
294 	clp->magic2 = lp->d_magic2;
295 	clp->checksum = lp->d_checksum;
296 	clp->partitions = lp->d_npartitions;
297 	clp->bbsize = lp->d_bbsize;
298 	clp->sbsize = lp->d_sbsize;
299 	clp->checksum = lp->d_checksum;
300 	/* note: assume at least 4 partitions */
301 	memcpy(clp->vid_4, &lp->d_partitions[0], sizeof(struct partition) * 4);
302 	memset(clp->cfg_4, 0, sizeof(struct partition) * 12);
303 	memcpy(clp->cfg_4, &lp->d_partitions[4], sizeof(struct partition)
304 	    * ((MAXPARTITIONS < 16) ? (MAXPARTITIONS - 4) : 12));
305 
306 	/*
307 	 * here are the parts of the cpu_disklabel the kernel must init.
308 	 * see disklabel.h for more details
309 	 * [note: this used to be handled by 'wrtvid']
310 	 */
311 	memcpy(clp->vid_id, VID_ID, sizeof(clp->vid_id));
312 	clp->vid_oss = VID_OSS;
313 	clp->vid_osl = VID_OSL;
314 	clp->vid_osa_u = VID_OSAU;
315 	clp->vid_osa_l = VID_OSAL;
316 	clp->vid_cas = VID_CAS;
317 	clp->vid_cal = VID_CAL;
318 	memcpy(clp->vid_mot, VID_MOT, sizeof(clp->vid_mot));
319 	clp->cfg_rec = CFG_REC;
320 	clp->cfg_psm = CFG_PSM;
321 }
322 
323 static void
324 cputobsdlabel(struct disklabel *lp, struct cpu_disklabel *clp)
325 {
326 	int i;
327 
328 	lp->d_magic = clp->magic1;
329 	lp->d_type = clp->type;
330 	lp->d_subtype = clp->subtype;
331 	strncpy(lp->d_typename, clp->vid_vd, 16);
332 	strncpy(lp->d_packname, clp->packname, 16);
333 	lp->d_secsize = clp->cfg_psm;
334 	lp->d_nsectors = clp->cfg_spt;
335 	lp->d_ncylinders = clp->cfg_trk; /* trk is really num of cyl! */
336 	lp->d_ntracks = clp->cfg_hds;
337 
338 	lp->d_secpercyl = clp->secpercyl;
339 	lp->d_secperunit = clp->secperunit;
340 	lp->d_secpercyl = clp->secpercyl;
341 	lp->d_secperunit = clp->secperunit;
342 	lp->d_sparespertrack = clp->sparespertrack;
343 	lp->d_sparespercyl = clp->sparespercyl;
344 	lp->d_acylinders = clp->acylinders;
345 	lp->d_rpm = clp->rpm;
346 	lp->d_interleave = clp->cfg_ilv;
347 	lp->d_trackskew = clp->cfg_sof;
348 	lp->d_cylskew = clp->cylskew;
349 	lp->d_headswitch = clp->headswitch;
350 
351 	/* this silly table is for winchester drives */
352 	switch (clp->cfg_ssr) {
353 	case 0:
354 		lp->d_trkseek = 0;
355 		break;
356 	case 1:
357 		lp->d_trkseek = 6;
358 		break;
359 	case 2:
360 		lp->d_trkseek = 10;
361 		break;
362 	case 3:
363 		lp->d_trkseek = 15;
364 		break;
365 	case 4:
366 		lp->d_trkseek = 20;
367 		break;
368 	default:
369 		lp->d_trkseek = 0;
370 	}
371 	lp->d_flags = clp->flags;
372 	for (i = 0; i < NDDATA; i++)
373 		lp->d_drivedata[i] = clp->drivedata[i];
374 	for (i = 0; i < NSPARE; i++)
375 		lp->d_spare[i] = clp->spare[i];
376 
377 	lp->d_magic2 = clp->magic2;
378 	lp->d_checksum = clp->checksum;
379 	lp->d_npartitions = clp->partitions;
380 	lp->d_bbsize = clp->bbsize;
381 	lp->d_sbsize = clp->sbsize;
382 	/* note: assume at least 4 partitions */
383 	memcpy(&lp->d_partitions[0], clp->vid_4, sizeof(struct partition) * 4);
384 	memcpy(&lp->d_partitions[4], clp->cfg_4, sizeof(struct partition)
385 	    * ((MAXPARTITIONS < 16) ? (MAXPARTITIONS - 4) : 12));
386 	lp->d_checksum = 0;
387 	lp->d_checksum = dkcksum(lp);
388 #if DEBUG
389 	if (disksubr_debug > 0) {
390 		printlp(lp, "translated label read from disk\n");
391 	}
392 #endif
393 }
394 
395 #ifdef DEBUG
396 static void
397 printlp(struct disklabel *lp, const char *str)
398 {
399 	int i;
400 
401 	printf("%s\n", str);
402 	printf("magic1 %x\n", lp->d_magic);
403 	printf("magic2 %x\n", lp->d_magic2);
404 	printf("typename %s\n", lp->d_typename);
405 	printf("secsize %x nsect %x ntrack %x ncylinders %x\n",
406 	    lp->d_secsize, lp->d_nsectors, lp->d_ntracks, lp->d_ncylinders);
407 	printf("Num partitions %x\n", lp->d_npartitions);
408 	for (i = 0; i < lp->d_npartitions; i++) {
409 		struct partition *part = &lp->d_partitions[i];
410 		const char *fstyp = fstypenames[part->p_fstype];
411 
412 		printf("%c: size %10x offset %10x type %7s frag %5x cpg %3x\n",
413 		    'a' + i, part->p_size, part->p_offset, fstyp,
414 		    part->p_frag, part->p_cpg);
415 	}
416 }
417 
418 static void
419 printclp(struct cpu_disklabel *clp, const char *str)
420 {
421 	int maxp, i;
422 
423 	printf("%s\n", str);
424 	printf("magic1 %lx\n", clp->magic1);
425 	printf("magic2 %lx\n", clp->magic2);
426 	printf("typename %s\n", clp->vid_vd);
427 	printf("secsize %x nsect %x ntrack %x ncylinders %x\n",
428 	    clp->cfg_psm, clp->cfg_spt, clp->cfg_hds, clp->cfg_trk);
429 	printf("Num partitions %x\n", clp->partitions);
430 	maxp = clp->partitions < 16 ? clp->partitions : 16;
431 	for (i = 0; i < maxp; i++) {
432 		struct partition *part;
433 		const char *fstyp;
434 
435 		if (i < 4) {
436 			part = (void *)&clp->vid_4[0];
437 			part = &part[i];
438 		} else {
439 			part = (void *)&clp->cfg_4[0];
440 			part = &part[i-4];
441 		}
442 
443 		fstyp = fstypenames[part->p_fstype];
444 
445 		printf("%c: size %10x offset %10x type %7s frag %5x cpg %3x\n",
446 		    'a' + i, part->p_size, part->p_offset, fstyp,
447 		    part->p_frag, part->p_cpg);
448 	}
449 }
450 #endif
451