xref: /netbsd-src/sys/arch/atari/atari/disksubr.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
1 /*	$NetBSD: disksubr.c,v 1.1.1.1 1995/03/26 07:12:18 leo Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Leo Weppelman.
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 Leo Weppelman.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/buf.h>
35 #include <sys/disklabel.h>
36 #include <machine/tospart.h>
37 
38 #define b_cylin b_resid
39 #define baddr(bp) (void *)((bp)->b_un.b_addr)
40 
41 /*
42  * Stash TOS partition info in here before handling.
43  */
44 typedef struct {
45 	u_long	nblocks;
46 	u_long	blkoff;
47 	u_long	type;
48 } TMP_PART;
49 
50 #define	ROOT_FLAG	0x8000	/* Added in TMP_PART.type when NBR	*/
51 
52 static char *rd_tosparts __P((TMP_PART *,dev_t,void (*)(),struct disklabel *));
53 static int	get_type __P((u_char *));
54 
55 /* XXX unknown function but needed for /sys/scsi to link */
56 int
57 dk_establish()
58 {
59 	return(-1);
60 }
61 
62 /*
63  * Attempt to read a disk label from a device
64  * using the indicated stategy routine.
65  * The label must be partly set up before this:
66  * secpercyl and anything required in the strategy routine
67  * (e.g., sector size) must be filled in before calling us.
68  * Returns null on success and an error string on failure.
69  */
70 char *
71 readdisklabel(dev, strat, lp, clp)
72 dev_t			dev;
73 void			(*strat)();
74 struct disklabel	*lp;
75 struct cpu_disklabel	*clp;
76 {
77 	TMP_PART	sizes[TOS_MAXPART];
78 	char		*msg;
79 	int		i;
80 	int		usr_part = RAW_PART;
81 
82 	bzero(sizes, sizeof(sizes));
83 	if((msg = rd_tosparts(sizes, dev, strat, lp)) != NULL)
84 		return(msg);
85 
86 	/*
87 	 * give some guarnteed validity to
88 	 * the disklabel
89 	 */
90 	if(lp->d_secperunit == 0)
91 		lp->d_secperunit = 0x1fffffff;
92 	if(lp->d_secpercyl == 0)
93 		return("Zero secpercyl");
94 	lp->d_npartitions = RAW_PART + 1;
95 
96 	for(i = 0; i < MAXPARTITIONS; i++) {
97 		if(i == RAW_PART)
98 			continue;
99 		lp->d_partitions[i].p_size   = 0;
100 		lp->d_partitions[i].p_offset = 0;
101 	}
102 
103 	/*
104 	 * Now map the partition table from TOS to the NetBSD table.
105 	 *
106 	 * This means:
107 	 *  Part 0   : Root
108 	 *  Part 1   : Swap
109 	 *  Part 2   : Whole disk
110 	 *  Part 3.. : User partitions
111 	 *
112 	 * When more than one root partition is found, the only the first one
113 	 * will be recognized as such. The others are mapped as user partitions.
114 	 */
115 	lp->d_partitions[RAW_PART].p_size   = sizes[0].nblocks;
116 	lp->d_partitions[RAW_PART].p_offset = sizes[0].blkoff;
117 
118 	for(i = 0; sizes[i].nblocks; i++) {
119 		int		have_root = 0;
120 		int		pno;
121 
122 		if(!have_root && (sizes[i].type & ROOT_FLAG)) {
123 			lp->d_partitions[0].p_size   = sizes[i].nblocks;
124 			lp->d_partitions[0].p_offset = sizes[i].blkoff;
125 			lp->d_partitions[0].p_fstype = FS_BSDFFS;
126 			have_root++;
127 			continue;
128 		}
129 		switch(sizes[i].type &= ~ROOT_FLAG) {
130 			case FS_SWAP:
131 					pno = 1;
132 					break;
133 			case FS_BSDFFS:
134 			case FS_MSDOS:
135 					pno = ++usr_part;
136 					break;
137 			default:
138 					continue;
139 		}
140 		if(pno >= MAXPARTITIONS)
141 			break; /* XXX */
142 		lp->d_partitions[pno].p_size   = sizes[i].nblocks;
143 		lp->d_partitions[pno].p_offset = sizes[i].blkoff;
144 		lp->d_partitions[pno].p_fstype = sizes[i].type;
145 	}
146 	lp->d_npartitions = usr_part + 1;
147 	lp->d_secperunit  = sizes[0].nblocks;
148 
149 	/*
150 	 * calulate new checksum.
151 	 */
152 	lp->d_magic = lp->d_magic2 = DISKMAGIC;
153 	lp->d_checksum = 0;
154 	lp->d_checksum = dkcksum(lp);
155 
156 	return(NULL);
157 }
158 
159 /*
160  * Check new disk label for sensibility
161  * before setting it.
162  */
163 int
164 setdisklabel(olp, nlp, openmask, clp)
165 register struct disklabel *olp, *nlp;
166 u_long openmask;
167 struct cpu_disklabel *clp;
168 {
169 	return (EINVAL);
170 }
171 
172 /*
173  * Write disk label back to device after modification.
174  */
175 int
176 writedisklabel(dev, strat, lp, clp)
177 	dev_t dev;
178 	void (*strat)();
179 	register struct disklabel *lp;
180 	struct cpu_disklabel *clp;
181 {
182 	return(EINVAL);
183 }
184 
185 
186 int
187 bounds_check_with_label(bp, lp, wlabel)
188 struct buf		*bp;
189 struct disklabel	*lp;
190 int			wlabel;
191 {
192 	struct partition	*pp;
193 	long			maxsz, sz;
194 
195 	pp = &lp->d_partitions[DISKPART(bp->b_dev)];
196 	if(bp->b_flags & B_RAW) {
197 		maxsz = pp->p_size * (lp->d_secsize / DEV_BSIZE);
198 		sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
199 	}
200 	else {
201 		maxsz = pp->p_size;
202 		sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
203 	}
204 
205 	if(bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
206 		if(bp->b_blkno == maxsz) {
207 			/*
208 			 * trying to get one block beyond return EOF.
209 			 */
210 			bp->b_resid = bp->b_bcount;
211 			return(0);
212 		}
213 		sz = maxsz - bp->b_blkno;
214 		if(sz <= 0 || bp->b_blkno < 0) {
215 			bp->b_error = EINVAL;
216 			bp->b_flags |= B_ERROR;
217 			return(-1);
218 		}
219 		/*
220 		 * adjust count down
221 		 */
222 		if(bp->b_flags & B_RAW)
223 			bp->b_bcount = sz << DEV_BSHIFT;
224 		else bp->b_bcount = sz * lp->d_secsize;
225 	}
226 
227 	/*
228 	 * calc cylinder for disksort to order transfers with
229 	 */
230 	bp->b_cylin = (bp->b_blkno + pp->p_offset) / lp->d_secpercyl;
231 	return(1);
232 }
233 
234 /*
235  * Read a GEM-partition info and translate it to our temporary partitions array.
236  * Returns 0 if an error occured, 1 if all went ok.
237  */
238 #define	BP_SETUP(bp, block) {						\
239 			bp->b_blkno  = block;				\
240 			bp->b_cylin  = block / lp->d_secpercyl;		\
241 			bp->b_bcount = TOS_BSIZE;			\
242 			bp->b_flags  = B_BUSY | B_READ;			\
243 		}
244 
245 static char *
246 rd_tosparts(sizes, dev, strat, lp)
247 TMP_PART		*sizes;
248 dev_t			dev;
249 void			(*strat)();
250 struct disklabel	*lp;
251 {
252 	GEM_ROOT	*g_root;
253 	GEM_PART	g_local[NGEM_PARTS];
254 	struct buf	*bp;
255 	int		pno  = 1;
256 	char		*msg = NULL;
257 	int		i;
258 
259 	/*
260 	 * Get a buffer first, so we can read the disk.
261 	 */
262 	bp = (void*)geteblk(TOS_BSIZE);
263 	bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART);
264 
265 	/*
266 	 * Read root sector
267 	 */
268 	BP_SETUP(bp, TOS_BBLOCK);
269 	strat(bp);
270 	if(biowait(bp)) {
271 		msg = "I/O error";
272 		goto done;
273 	}
274 
275 	/*
276 	 * Make local copy of partition info, we may need to re-use
277 	 * the buffer in case of 'XGM' partitions.
278 	 */
279 	g_root  = (GEM_ROOT*)baddr(bp);
280 	bcopy(g_root->parts, g_local, NGEM_PARTS*sizeof(GEM_PART));
281 
282 	/*
283 	 * Partition 0 contains whole disk!
284 	 */
285 	sizes[0].nblocks = g_root->hd_siz;
286 	sizes[0].blkoff  = 0;
287 	sizes[0].type    = FS_UNUSED;
288 
289 	for(i = 0; i < NGEM_PARTS; i++) {
290 	    if(!(g_local[i].p_flg & 1))
291 		continue;
292 	    if(!strncmp(g_local[i].p_id, "XGM", 3)) {
293 		int	j;
294 		daddr_t	new_root = g_local[i].p_st;
295 
296 		/*
297 		 * Loop through extended partition list
298 		 */
299 		for(;;) {
300 		    BP_SETUP(bp, new_root);
301 		    strat(bp);
302 		    if(biowait(bp)) {
303 				msg = "I/O error";
304 				goto done;
305 		    }
306 		    for(j = 0; j < NGEM_PARTS; j++) {
307 			if(!(g_root->parts[j].p_flg & 1))
308 				continue;
309 			if(!strncmp(g_root->parts[j].p_id, "XGM", 3)) {
310 			    new_root = g_local[i].p_st + g_root->parts[j].p_st;
311 			    break;
312 			}
313 			else {
314 			    sizes[pno].nblocks=g_root->parts[j].p_size;
315 			    sizes[pno].blkoff =g_root->parts[j].p_st+new_root;
316 			    sizes[pno].type   =get_type(g_root->parts[j].p_id);
317 			    pno++;
318 			    if(pno >= TOS_MAXPART)
319 				break;
320 			}
321 		    }
322 		    if(j == NGEM_PARTS)
323 			break;
324 		}
325 	    }
326 	    else {
327 		sizes[pno].nblocks = g_local[i].p_size;
328 		sizes[pno].blkoff  = g_local[i].p_st;
329 		sizes[pno].type    = get_type(g_local[i].p_id);
330 		pno++;
331 	    }
332 	}
333 	/*
334 	 * Check sensibility of partition info
335 	 */
336 	for(i = 2; i < pno; i++) {
337 		if(sizes[i].blkoff < (sizes[i-1].blkoff + sizes[i-1].nblocks)) {
338 			msg = "Partion table bad (overlap)";
339 			goto done;
340 		}
341 		if((sizes[i].blkoff + sizes[i].nblocks) > sizes[0].nblocks) {
342 			msg = "Partion table bad (extends beyond disk)";
343 			goto done;
344 		}
345 	}
346 done:
347 	bp->b_flags = B_INVAL | B_AGE | B_READ;
348 	brelse(bp);
349 	return(msg);
350 }
351 
352 /*
353  * Translate a TOS partition type to a NetBSD partition type.
354  */
355 #define	ID_CMP(a,b)	((a[0] == b[0]) && (a[1] == b[1]) && (a[2] == b[2]))
356 
357 static int
358 get_type(p_id)
359 u_char	*p_id;
360 {
361 	if(ID_CMP(p_id, "GEM") || ID_CMP(p_id, "BGM"))
362 		return(FS_MSDOS); /* XXX - should be compatible */
363 	if(ID_CMP(p_id, "NBU"))
364 		return(FS_BSDFFS);
365 	if(ID_CMP(p_id, "NBR"))
366 		return(FS_BSDFFS|ROOT_FLAG);
367 	if(ID_CMP(p_id, "NBS"))
368 		return(FS_SWAP);
369 	return(FS_OTHER);
370 }
371