write.c revision 1.3 1 /* $NetBSD: write.c,v 1.3 2005/06/10 22:08:39 he 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