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 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 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 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 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