write.c revision 1.5 1 /* $NetBSD: write.c,v 1.5 2008/04/28 20:23:15 martin 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
52 ahdi_writelabel (ptable, diskname, flags)
53 struct ahdi_ptable *ptable;
54 char *diskname;
55 int flags;
56 {
57 int fd, i, j, k, firstxgm, keep, cksum_ok;
58 struct ahdi_root *root;
59 u_int rsec;
60 u_int32_t xgmsec, nbdsec;
61
62 if (!(fd = openraw (diskname, O_RDWR)))
63 return (-1);
64
65 if ((i = ahdi_checklabel (ptable)) < 0) {
66 close (fd);
67 return (i);
68 }
69
70 if (flags & AHDI_KEEP_BOOT) {
71 if ((root = disk_read (fd, AHDI_BBLOCK, 1)) == NULL) {
72 return (-1);
73 }
74 cksum_ok = ahdi_cksum (root) == root->ar_checksum;
75 #ifdef DEBUG
76 printf ("Previous root sector checksum was ");
77 cksum_ok ? printf (" correct\n") : printf (" incorrect\n");
78 #endif
79 bzero ((void *) root->ar_parts,
80 sizeof (struct ahdi_part) * AHDI_MAXRPD);
81 } else {
82 if ((root = malloc (sizeof (struct ahdi_root))) == NULL) {
83 close (fd);
84 return (-1);
85 }
86 bzero ((void *) root, sizeof (struct ahdi_root));
87 cksum_ok = 0;
88 #ifdef DEBUG
89 printf ("Clearing root sector - forcing incorrect checksum\n");
90 #endif
91 }
92
93 nbdsec = 0;
94 #ifdef DEBUG
95 printf ("Writing root sector\n");
96 #endif
97
98 /* All partitions in root sector (including first XGM) */
99 j = 0;
100 firstxgm = 0;
101 xgmsec = 0;
102 for (i = 0; i < ptable->nparts; i++) {
103 if (ptable->parts[i].root == 0) {
104 #ifdef DEBUG
105 printf (" Partition %d - ", j);
106 #endif
107 root->ar_parts[j].ap_flg = 0x01;
108 for (k = 0; k < 3; k++) {
109 root->ar_parts[j].ap_id[k] =
110 ptable->parts[i].id[k];
111 #ifdef DEBUG
112 printf ("%c", root->ar_parts[j].ap_id[k]);
113 #endif
114 }
115 root->ar_parts[j].ap_st = ptable->parts[i].start;
116 root->ar_parts[j].ap_size = ptable->parts[i].size;
117 #ifdef DEBUG
118 printf ("/%u/%u\n", root->ar_parts[j].ap_st,
119 root->ar_parts[j].ap_size);
120 #endif
121
122 j++;
123 } else if (!firstxgm) {
124 root->ar_parts[j].ap_flg = 0x01;
125 root->ar_parts[j].ap_id[0] = 'X';
126 root->ar_parts[j].ap_id[1] = 'G';
127 root->ar_parts[j].ap_id[2] = 'M';
128 root->ar_parts[j].ap_st = ptable->parts[i].root;
129 root->ar_parts[j].ap_size = ptable->parts[i].size + 1;
130 firstxgm = i;
131 xgmsec = ptable->parts[i].root;
132 #ifdef DEBUG
133 printf (" Partition %d - XGM/%u/%u\n", j,
134 root->ar_parts[j].ap_st,
135 root->ar_parts[j].ap_size);
136 #endif
137 j++;
138 }
139 /*
140 * Note first netbsd partition for invalidate_netbsd_label().
141 */
142 if (!nbdsec && AHDI_MKPID (ptable->parts[i].id[0],
143 ptable->parts[i].id[1], ptable->parts[i].id[2])
144 == AHDI_PID_NBD) {
145 nbdsec = ptable->parts[i].start;
146 }
147 }
148
149 root->ar_hdsize = ptable->secperunit;
150 if (!(flags & AHDI_KEEP_BSL)) {
151 root->ar_bslst = (u_int32_t) BSL_OFFSET;
152 root->ar_bslsize = (u_int32_t) BSL_SIZE;
153 }
154
155 /* Write correct checksum? */
156 root->ar_checksum = ahdi_cksum (root);
157 if (!cksum_ok) {
158 root->ar_checksum ^= 0x5555;
159 #ifdef DEBUG
160 printf ("Setting incorrect checksum\n");
161 } else {
162 printf ("Setting correct checksum\n");
163 #endif
164 }
165
166 if (!disk_write (fd, AHDI_BBLOCK, 1, root)) {
167 free (root);
168 close (fd);
169 return (-1);
170 }
171
172 /* Auxiliary roots */
173 for (i = firstxgm; i < ptable->nparts; i++) {
174 j = 0;
175 if (ptable->parts[i].root == 0)
176 continue;
177 #ifdef DEBUG
178 printf ("Writing auxiliary root at sector %u\n",
179 ptable->parts[i].root);
180 #endif
181 bzero ((void *) root, sizeof (struct ahdi_root));
182 rsec = ptable->parts[i].root;
183 #ifdef DEBUG
184 printf (" Partition %d - ", j);
185 #endif
186 root->ar_parts[j].ap_flg = 0x01;
187 for (k = 0; k < 3; k++) {
188 root->ar_parts[j].ap_id[k] =
189 ptable->parts[i].id[k];
190 #ifdef DEBUG
191 printf ("%c", root->ar_parts[j].ap_id[k]);
192 #endif
193 }
194 root->ar_parts[j].ap_st = ptable->parts[i].start -
195 rsec;
196 root->ar_parts[j].ap_size = ptable->parts[i].size;
197 #ifdef DEBUG
198 printf ("/%u/%u\n", root->ar_parts[j].ap_st,
199 root->ar_parts[j].ap_size);
200 #endif
201 j++;
202 if (i < ptable->nparts - 1) {
203 /* Need an XGM? */
204 if (ptable->parts[i].root != ptable->parts[i+1].root &&
205 ptable->parts[i+1].root != 0) {
206 root->ar_parts[j].ap_flg = 0x01;
207 root->ar_parts[j].ap_id[0] = 'X';
208 root->ar_parts[j].ap_id[1] = 'G';
209 root->ar_parts[j].ap_id[2] = 'M';
210 root->ar_parts[j].ap_st =
211 ptable->parts[i+1].root - xgmsec;
212 root->ar_parts[j].ap_size =
213 ptable->parts[i+1].size + 1;
214 #ifdef DEBUG
215 printf (" Partition %d - XGM/%u/%u\n", j,
216 root->ar_parts[j].ap_st,
217 root->ar_parts[j].ap_size);
218 #endif
219 }
220 if (ptable->parts[i].root == ptable->parts[i+1].root) {
221 /* Next partition has same auxiliary root */
222 #ifdef DEBUG
223 printf (" Partition %d - ", j);
224 #endif
225 root->ar_parts[j].ap_flg = 0x01;
226 for (k = 0; k < 3; k++) {
227 root->ar_parts[j].ap_id[k] =
228 ptable->parts[i+1].id[k];
229 #ifdef DEBUG
230 printf ("%c", root->ar_parts[j].ap_id[k]);
231 #endif
232 }
233 root->ar_parts[j].ap_st =
234 ptable->parts[i+1].start - rsec;
235 root->ar_parts[j].ap_size =
236 ptable->parts[i+1].size;
237 #ifdef DEBUG
238 printf ("/%u/%u\n", root->ar_parts[j].ap_st,
239 root->ar_parts[j].ap_size);
240 #endif
241 i++;
242 }
243 j++;
244 }
245
246 if (!disk_write (fd, rsec, 1, root)) {
247 close (fd);
248 free (root);
249 return (-1);
250 }
251
252 /*
253 * Note first netbsd partition for invalidate_netbsd_label().
254 */
255 if (!nbdsec && AHDI_MKPID (ptable->parts[i].id[0],
256 ptable->parts[i].id[1], ptable->parts[i].id[2])
257 == AHDI_PID_NBD) {
258 nbdsec = ptable->parts[i].start;
259 }
260 }
261
262 free (root);
263
264 if (!(flags & AHDI_KEEP_BSL) && !write_bsl (fd)) {
265 close (fd);
266 return (-1);
267 }
268
269 if (!(flags & AHDI_KEEP_NBDA) && !invalidate_netbsd_label(fd, nbdsec)) {
270 close (fd);
271 return (-1);
272 }
273
274 #ifdef DEBUG
275 printf ("Forcing disk label re-read\n");
276 #endif
277 keep = 0;
278 if (ioctl (fd, DIOCKLABEL, &keep) < 0) {
279 close (fd);
280 return (-1);
281 }
282
283 close (fd);
284 return (1);
285 }
286
287 /*
288 * Write a bad sector list (empty).
289 */
290 int
291 write_bsl (fd)
292 int fd;
293 {
294 u_int8_t *bsl;
295
296 if ((bsl = malloc (sizeof (u_int8_t) * BSL_SIZE * DEV_BSIZE)) == NULL)
297 return (0);
298 bzero ((void *) bsl, sizeof (u_int8_t) * DEV_BSIZE);
299
300 #ifdef DEBUG
301 printf ("Writing bad sector list\n");
302 #endif
303 bsl[3] = BSL_MAGIC;
304 if (!disk_write (fd, (u_int) BSL_OFFSET, (u_int) BSL_SIZE, bsl)) {
305 free (bsl);
306 return (0);
307 }
308 free (bsl);
309 return (1);
310 }
311
312 /*
313 * Invalidate any previous AHDI/NBDA disklabel.
314 * Otherwise this make take precedence when we next open the disk.
315 */
316 int
317 invalidate_netbsd_label (fd, nbdsec)
318 int fd;
319 u_int32_t nbdsec;
320 {
321 struct bootblock *bb;
322 u_int nsec;
323
324 nsec = (BBMINSIZE + (DEV_BSIZE - 1)) / DEV_BSIZE;
325
326 if ((bb = disk_read (fd, nbdsec, nsec)) == NULL) {
327 return (0);
328 }
329
330 if (bb->bb_magic == NBDAMAGIC || bb->bb_magic == AHDIMAGIC) {
331 bb->bb_magic = bb->bb_magic & 0xffffff00;
332 bb->bb_magic = bb->bb_magic | 0x5f;
333
334 #ifdef DEBUG
335 printf ("Invalidating old NBDA/AHDI label (sector %u)\n",
336 nbdsec);
337 #endif
338 if (!disk_write (fd, nbdsec, nsec, bb)) {
339 free (bb);
340 return (0);
341 }
342 }
343
344 free (bb);
345 return (1);
346 }
347
348 int
349 disk_write (fd, start, count, buf)
350 int fd;
351 u_int start,
352 count;
353 void *buf;
354 {
355 off_t offset;
356 size_t size;
357
358 size = count * DEV_BSIZE;
359 offset = start * DEV_BSIZE;
360
361 if (lseek (fd, offset, SEEK_SET) != offset)
362 return (0);
363 if (write (fd, buf, size) != size)
364 return (0);
365 return (1);
366 }
367