xref: /netbsd-src/sys/arch/atari/stand/ahdilabel/write.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: write.c,v 1.4 2005/12/11 12:17:00 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1999 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Julian Coleman, Waldi Ravens and Leo Weppelman.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include "privahdi.h"
40 #include <fcntl.h>
41 #ifdef DEBUG
42 #include <stdio.h>
43 #endif
44 #include <stdlib.h>
45 #include <strings.h>
46 #include <unistd.h>
47 #include <sys/dkio.h>
48 #include <sys/ioctl.h>
49 
50 #define BSL_MAGIC	0xa5
51 #define BSL_OFFSET	1
52 #define BSL_SIZE	1
53 
54 /*
55  * Write AHDI partitions to disk
56  */
57 
58 int
59 ahdi_writelabel (ptable, diskname, flags)
60 	struct ahdi_ptable	*ptable;
61 	char			*diskname;
62 	int			 flags;
63 {
64 	int			 fd, i, j, k, firstxgm, keep, cksum_ok;
65 	struct ahdi_root	*root;
66 	u_int			 rsec;
67 	u_int32_t		 xgmsec, nbdsec;
68 
69 	if (!(fd = openraw (diskname, O_RDWR)))
70 		return (-1);
71 
72 	if ((i = ahdi_checklabel (ptable)) < 0) {
73 		close (fd);
74 		return (i);
75 	}
76 
77 	if (flags & AHDI_KEEP_BOOT) {
78 		if ((root = disk_read (fd, AHDI_BBLOCK, 1)) == NULL) {
79 			return (-1);
80 		}
81 		cksum_ok = ahdi_cksum (root) == root->ar_checksum;
82 #ifdef DEBUG
83 		printf ("Previous root sector checksum was ");
84 		cksum_ok ? printf (" correct\n") : printf (" incorrect\n");
85 #endif
86 		bzero ((void *) root->ar_parts,
87 		    sizeof (struct ahdi_part) * AHDI_MAXRPD);
88 	} else {
89 		if ((root = malloc (sizeof (struct ahdi_root))) == NULL) {
90 			close (fd);
91 			return (-1);
92 		}
93 		bzero ((void *) root, sizeof (struct ahdi_root));
94 		cksum_ok = 0;
95 #ifdef DEBUG
96 		printf ("Clearing root sector - forcing incorrect checksum\n");
97 #endif
98 	}
99 
100 	nbdsec = 0;
101 #ifdef DEBUG
102 	printf ("Writing root sector\n");
103 #endif
104 
105         /* All partitions in root sector (including first XGM) */
106 	j = 0;
107 	firstxgm = 0;
108 	xgmsec = 0;
109 	for (i = 0; i < ptable->nparts; i++) {
110 		if (ptable->parts[i].root == 0) {
111 #ifdef DEBUG
112 			printf ("  Partition %d - ", j);
113 #endif
114 			root->ar_parts[j].ap_flg = 0x01;
115 			for (k = 0; k < 3; k++) {
116 				root->ar_parts[j].ap_id[k] =
117 				    ptable->parts[i].id[k];
118 #ifdef DEBUG
119 				printf ("%c", root->ar_parts[j].ap_id[k]);
120 #endif
121 			}
122 			root->ar_parts[j].ap_st = ptable->parts[i].start;
123 			root->ar_parts[j].ap_size = ptable->parts[i].size;
124 #ifdef DEBUG
125 			printf ("/%u/%u\n", root->ar_parts[j].ap_st,
126 			    root->ar_parts[j].ap_size);
127 #endif
128 
129 			j++;
130 		} else if (!firstxgm) {
131 			root->ar_parts[j].ap_flg = 0x01;
132 			root->ar_parts[j].ap_id[0] = 'X';
133 			root->ar_parts[j].ap_id[1] = 'G';
134 			root->ar_parts[j].ap_id[2] = 'M';
135 			root->ar_parts[j].ap_st = ptable->parts[i].root;
136 			root->ar_parts[j].ap_size = ptable->parts[i].size + 1;
137 			firstxgm = i;
138 			xgmsec = ptable->parts[i].root;
139 #ifdef DEBUG
140 			printf ("  Partition %d - XGM/%u/%u\n", j,
141 			    root->ar_parts[j].ap_st,
142 			    root->ar_parts[j].ap_size);
143 #endif
144 			j++;
145 		}
146 		/*
147 		 * Note first netbsd partition for invalidate_netbsd_label().
148 		 */
149 		if (!nbdsec && AHDI_MKPID (ptable->parts[i].id[0],
150 		    ptable->parts[i].id[1], ptable->parts[i].id[2])
151 		    == AHDI_PID_NBD) {
152 			nbdsec = ptable->parts[i].start;
153 		}
154 	}
155 
156 	root->ar_hdsize = ptable->secperunit;
157 	if (!(flags & AHDI_KEEP_BSL)) {
158 		root->ar_bslst = (u_int32_t) BSL_OFFSET;
159 		root->ar_bslsize = (u_int32_t) BSL_SIZE;
160 	}
161 
162 	/* Write correct checksum? */
163 	root->ar_checksum = ahdi_cksum (root);
164 	if (!cksum_ok) {
165 		root->ar_checksum ^= 0x5555;
166 #ifdef DEBUG
167 		printf ("Setting incorrect checksum\n");
168 	} else {
169 		printf ("Setting correct checksum\n");
170 #endif
171 	}
172 
173 	if (!disk_write (fd, AHDI_BBLOCK, 1, root)) {
174 		free (root);
175 		close (fd);
176 		return (-1);
177 	}
178 
179 	/* Auxiliary roots */
180 	for (i = firstxgm; i < ptable->nparts; i++) {
181 		j = 0;
182 		if (ptable->parts[i].root == 0)
183 			continue;
184 #ifdef DEBUG
185 	printf ("Writing auxiliary root at sector %u\n",
186 	    ptable->parts[i].root);
187 #endif
188 		bzero ((void *) root, sizeof (struct ahdi_root));
189 		rsec = ptable->parts[i].root;
190 #ifdef DEBUG
191 			printf ("  Partition %d - ", j);
192 #endif
193 		root->ar_parts[j].ap_flg = 0x01;
194 		for (k = 0; k < 3; k++) {
195 			root->ar_parts[j].ap_id[k] =
196 			    ptable->parts[i].id[k];
197 #ifdef DEBUG
198 			printf ("%c", root->ar_parts[j].ap_id[k]);
199 #endif
200 		}
201 		root->ar_parts[j].ap_st = ptable->parts[i].start -
202 		    rsec;
203 		root->ar_parts[j].ap_size = ptable->parts[i].size;
204 #ifdef DEBUG
205 		printf ("/%u/%u\n", root->ar_parts[j].ap_st,
206 		    root->ar_parts[j].ap_size);
207 #endif
208 		j++;
209 		if (i < ptable->nparts - 1) {
210 			/* Need an XGM? */
211 			if (ptable->parts[i].root != ptable->parts[i+1].root &&
212 			    ptable->parts[i+1].root != 0) {
213 				root->ar_parts[j].ap_flg = 0x01;
214 				root->ar_parts[j].ap_id[0] = 'X';
215 				root->ar_parts[j].ap_id[1] = 'G';
216 				root->ar_parts[j].ap_id[2] = 'M';
217 				root->ar_parts[j].ap_st =
218 					ptable->parts[i+1].root - xgmsec;
219 				root->ar_parts[j].ap_size =
220 					ptable->parts[i+1].size + 1;
221 #ifdef DEBUG
222 				printf ("  Partition %d - XGM/%u/%u\n", j,
223 				    root->ar_parts[j].ap_st,
224 				    root->ar_parts[j].ap_size);
225 #endif
226 			}
227 			if (ptable->parts[i].root == ptable->parts[i+1].root) {
228 				/* Next partition has same auxiliary root */
229 #ifdef DEBUG
230 				printf ("  Partition %d - ", j);
231 #endif
232 				root->ar_parts[j].ap_flg = 0x01;
233 				for (k = 0; k < 3; k++) {
234 					root->ar_parts[j].ap_id[k] =
235 			    		ptable->parts[i+1].id[k];
236 #ifdef DEBUG
237 				printf ("%c", root->ar_parts[j].ap_id[k]);
238 #endif
239 				}
240 				root->ar_parts[j].ap_st =
241 				    ptable->parts[i+1].start - rsec;
242 				root->ar_parts[j].ap_size =
243 				    ptable->parts[i+1].size;
244 #ifdef DEBUG
245 				printf ("/%u/%u\n", root->ar_parts[j].ap_st,
246 				    root->ar_parts[j].ap_size);
247 #endif
248 				i++;
249 			}
250 			j++;
251 		}
252 
253 		if (!disk_write (fd, rsec, 1, root)) {
254 			close (fd);
255 			free (root);
256 			return (-1);
257 		}
258 
259 		/*
260 		 * Note first netbsd partition for invalidate_netbsd_label().
261 		 */
262 		if (!nbdsec && AHDI_MKPID (ptable->parts[i].id[0],
263 		    ptable->parts[i].id[1], ptable->parts[i].id[2])
264 		    == AHDI_PID_NBD) {
265 			nbdsec = ptable->parts[i].start;
266 		}
267 	}
268 
269 	free (root);
270 
271 	if (!(flags & AHDI_KEEP_BSL) && !write_bsl (fd)) {
272 		close (fd);
273 		return (-1);
274 	}
275 
276 	if (!(flags & AHDI_KEEP_NBDA) && !invalidate_netbsd_label(fd, nbdsec)) {
277 		close (fd);
278 		return (-1);
279 	}
280 
281 #ifdef DEBUG
282 	printf ("Forcing disk label re-read\n");
283 #endif
284 	keep = 0;
285 	if (ioctl (fd, DIOCKLABEL, &keep) < 0) {
286 		close (fd);
287 		return (-1);
288 	}
289 
290 	close (fd);
291 	return (1);
292 }
293 
294 /*
295  * Write a bad sector list (empty).
296  */
297 int
298 write_bsl (fd)
299 	int	fd;
300 {
301 	u_int8_t	*bsl;
302 
303 	if ((bsl = malloc (sizeof (u_int8_t) * BSL_SIZE * DEV_BSIZE)) == NULL)
304 		return (0);
305 	bzero ((void *) bsl, sizeof (u_int8_t) * DEV_BSIZE);
306 
307 #ifdef DEBUG
308 	printf ("Writing bad sector list\n");
309 #endif
310 	bsl[3] = BSL_MAGIC;
311 	if (!disk_write (fd, (u_int) BSL_OFFSET, (u_int) BSL_SIZE, bsl)) {
312 		free (bsl);
313 		return (0);
314 	}
315 	free (bsl);
316 	return (1);
317 }
318 
319 /*
320  * Invalidate any previous AHDI/NBDA disklabel.
321  * Otherwise this make take precedence when we next open the disk.
322  */
323 int
324 invalidate_netbsd_label (fd, nbdsec)
325 	int		 fd;
326 	u_int32_t	nbdsec;
327 {
328 	struct bootblock	*bb;
329 	u_int			 nsec;
330 
331 	nsec = (BBMINSIZE + (DEV_BSIZE - 1)) / DEV_BSIZE;
332 
333 	if ((bb = disk_read (fd, nbdsec, nsec)) == NULL) {
334 		return (0);
335 	}
336 
337 	if (bb->bb_magic == NBDAMAGIC || bb->bb_magic == AHDIMAGIC) {
338 		bb->bb_magic = bb->bb_magic & 0xffffff00;
339 		bb->bb_magic = bb->bb_magic | 0x5f;
340 
341 #ifdef DEBUG
342 		printf ("Invalidating old NBDA/AHDI label (sector %u)\n",
343 		    nbdsec);
344 #endif
345 		if (!disk_write (fd, nbdsec, nsec, bb)) {
346 			free (bb);
347 			return (0);
348 		}
349 	}
350 
351 	free (bb);
352 	return (1);
353 }
354 
355 int
356 disk_write (fd, start, count, buf)
357 	int	 fd;
358 	u_int	 start,
359 		 count;
360 	void	*buf;
361 {
362 	off_t	 offset;
363 	size_t	 size;
364 
365 	size   = count * DEV_BSIZE;
366 	offset = start * DEV_BSIZE;
367 
368 	if (lseek (fd, offset, SEEK_SET) != offset)
369 		return (0);
370 	if (write (fd, buf, size) != size)
371 		return (0);
372 	return (1);
373 }
374