1 /* $NetBSD: write.c,v 1.4 2005/12/11 12:17:00 christos 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