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