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