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