1 1.6 dsl /* $NetBSD: write.c,v 1.6 2009/03/14 21:04:06 dsl Exp $ */ 2 1.1 leo 3 1.1 leo /* 4 1.1 leo * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 1.1 leo * All rights reserved. 6 1.1 leo * 7 1.1 leo * This code is derived from software contributed to The NetBSD Foundation 8 1.1 leo * by Julian Coleman, Waldi Ravens and Leo Weppelman. 9 1.1 leo * 10 1.1 leo * Redistribution and use in source and binary forms, with or without 11 1.1 leo * modification, are permitted provided that the following conditions 12 1.1 leo * are met: 13 1.1 leo * 1. Redistributions of source code must retain the above copyright 14 1.1 leo * notice, this list of conditions and the following disclaimer. 15 1.1 leo * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 leo * notice, this list of conditions and the following disclaimer in the 17 1.1 leo * documentation and/or other materials provided with the distribution. 18 1.1 leo * 19 1.1 leo * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 leo * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 leo * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 leo * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 leo * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 leo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 leo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 leo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 leo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 leo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 leo * POSSIBILITY OF SUCH DAMAGE. 30 1.1 leo */ 31 1.1 leo 32 1.1 leo #include "privahdi.h" 33 1.1 leo #include <fcntl.h> 34 1.2 jdc #ifdef DEBUG 35 1.2 jdc #include <stdio.h> 36 1.2 jdc #endif 37 1.1 leo #include <stdlib.h> 38 1.1 leo #include <strings.h> 39 1.1 leo #include <unistd.h> 40 1.1 leo #include <sys/dkio.h> 41 1.1 leo #include <sys/ioctl.h> 42 1.1 leo 43 1.1 leo #define BSL_MAGIC 0xa5 44 1.1 leo #define BSL_OFFSET 1 45 1.1 leo #define BSL_SIZE 1 46 1.1 leo 47 1.1 leo /* 48 1.1 leo * Write AHDI partitions to disk 49 1.1 leo */ 50 1.1 leo 51 1.1 leo int 52 1.6 dsl ahdi_writelabel (struct ahdi_ptable *ptable, char *diskname, int flags) 53 1.1 leo { 54 1.2 jdc int fd, i, j, k, firstxgm, keep, cksum_ok; 55 1.1 leo struct ahdi_root *root; 56 1.1 leo u_int rsec; 57 1.1 leo u_int32_t xgmsec, nbdsec; 58 1.1 leo 59 1.1 leo if (!(fd = openraw (diskname, O_RDWR))) 60 1.1 leo return (-1); 61 1.1 leo 62 1.1 leo if ((i = ahdi_checklabel (ptable)) < 0) { 63 1.1 leo close (fd); 64 1.1 leo return (i); 65 1.1 leo } 66 1.1 leo 67 1.1 leo if (flags & AHDI_KEEP_BOOT) { 68 1.1 leo if ((root = disk_read (fd, AHDI_BBLOCK, 1)) == NULL) { 69 1.1 leo return (-1); 70 1.1 leo } 71 1.2 jdc cksum_ok = ahdi_cksum (root) == root->ar_checksum; 72 1.2 jdc #ifdef DEBUG 73 1.2 jdc printf ("Previous root sector checksum was "); 74 1.2 jdc cksum_ok ? printf (" correct\n") : printf (" incorrect\n"); 75 1.2 jdc #endif 76 1.1 leo bzero ((void *) root->ar_parts, 77 1.1 leo sizeof (struct ahdi_part) * AHDI_MAXRPD); 78 1.1 leo } else { 79 1.1 leo if ((root = malloc (sizeof (struct ahdi_root))) == NULL) { 80 1.1 leo close (fd); 81 1.1 leo return (-1); 82 1.1 leo } 83 1.1 leo bzero ((void *) root, sizeof (struct ahdi_root)); 84 1.2 jdc cksum_ok = 0; 85 1.2 jdc #ifdef DEBUG 86 1.2 jdc printf ("Clearing root sector - forcing incorrect checksum\n"); 87 1.2 jdc #endif 88 1.1 leo } 89 1.1 leo 90 1.1 leo nbdsec = 0; 91 1.1 leo #ifdef DEBUG 92 1.1 leo printf ("Writing root sector\n"); 93 1.1 leo #endif 94 1.1 leo 95 1.1 leo /* All partitions in root sector (including first XGM) */ 96 1.1 leo j = 0; 97 1.1 leo firstxgm = 0; 98 1.3 he xgmsec = 0; 99 1.1 leo for (i = 0; i < ptable->nparts; i++) { 100 1.1 leo if (ptable->parts[i].root == 0) { 101 1.1 leo #ifdef DEBUG 102 1.1 leo printf (" Partition %d - ", j); 103 1.1 leo #endif 104 1.1 leo root->ar_parts[j].ap_flg = 0x01; 105 1.1 leo for (k = 0; k < 3; k++) { 106 1.1 leo root->ar_parts[j].ap_id[k] = 107 1.1 leo ptable->parts[i].id[k]; 108 1.1 leo #ifdef DEBUG 109 1.1 leo printf ("%c", root->ar_parts[j].ap_id[k]); 110 1.1 leo #endif 111 1.1 leo } 112 1.1 leo root->ar_parts[j].ap_st = ptable->parts[i].start; 113 1.1 leo root->ar_parts[j].ap_size = ptable->parts[i].size; 114 1.1 leo #ifdef DEBUG 115 1.1 leo printf ("/%u/%u\n", root->ar_parts[j].ap_st, 116 1.1 leo root->ar_parts[j].ap_size); 117 1.1 leo #endif 118 1.1 leo 119 1.1 leo j++; 120 1.1 leo } else if (!firstxgm) { 121 1.1 leo root->ar_parts[j].ap_flg = 0x01; 122 1.1 leo root->ar_parts[j].ap_id[0] = 'X'; 123 1.1 leo root->ar_parts[j].ap_id[1] = 'G'; 124 1.1 leo root->ar_parts[j].ap_id[2] = 'M'; 125 1.1 leo root->ar_parts[j].ap_st = ptable->parts[i].root; 126 1.1 leo root->ar_parts[j].ap_size = ptable->parts[i].size + 1; 127 1.1 leo firstxgm = i; 128 1.1 leo xgmsec = ptable->parts[i].root; 129 1.1 leo #ifdef DEBUG 130 1.1 leo printf (" Partition %d - XGM/%u/%u\n", j, 131 1.1 leo root->ar_parts[j].ap_st, 132 1.1 leo root->ar_parts[j].ap_size); 133 1.1 leo #endif 134 1.1 leo j++; 135 1.1 leo } 136 1.1 leo /* 137 1.1 leo * Note first netbsd partition for invalidate_netbsd_label(). 138 1.1 leo */ 139 1.1 leo if (!nbdsec && AHDI_MKPID (ptable->parts[i].id[0], 140 1.1 leo ptable->parts[i].id[1], ptable->parts[i].id[2]) 141 1.1 leo == AHDI_PID_NBD) { 142 1.1 leo nbdsec = ptable->parts[i].start; 143 1.1 leo } 144 1.1 leo } 145 1.1 leo 146 1.1 leo root->ar_hdsize = ptable->secperunit; 147 1.1 leo if (!(flags & AHDI_KEEP_BSL)) { 148 1.1 leo root->ar_bslst = (u_int32_t) BSL_OFFSET; 149 1.1 leo root->ar_bslsize = (u_int32_t) BSL_SIZE; 150 1.1 leo } 151 1.2 jdc 152 1.2 jdc /* Write correct checksum? */ 153 1.1 leo root->ar_checksum = ahdi_cksum (root); 154 1.2 jdc if (!cksum_ok) { 155 1.2 jdc root->ar_checksum ^= 0x5555; 156 1.2 jdc #ifdef DEBUG 157 1.2 jdc printf ("Setting incorrect checksum\n"); 158 1.2 jdc } else { 159 1.2 jdc printf ("Setting correct checksum\n"); 160 1.2 jdc #endif 161 1.2 jdc } 162 1.1 leo 163 1.1 leo if (!disk_write (fd, AHDI_BBLOCK, 1, root)) { 164 1.1 leo free (root); 165 1.1 leo close (fd); 166 1.1 leo return (-1); 167 1.1 leo } 168 1.1 leo 169 1.1 leo /* Auxiliary roots */ 170 1.1 leo for (i = firstxgm; i < ptable->nparts; i++) { 171 1.1 leo j = 0; 172 1.1 leo if (ptable->parts[i].root == 0) 173 1.1 leo continue; 174 1.1 leo #ifdef DEBUG 175 1.1 leo printf ("Writing auxiliary root at sector %u\n", 176 1.1 leo ptable->parts[i].root); 177 1.1 leo #endif 178 1.1 leo bzero ((void *) root, sizeof (struct ahdi_root)); 179 1.1 leo rsec = ptable->parts[i].root; 180 1.1 leo #ifdef DEBUG 181 1.1 leo printf (" Partition %d - ", j); 182 1.1 leo #endif 183 1.1 leo root->ar_parts[j].ap_flg = 0x01; 184 1.1 leo for (k = 0; k < 3; k++) { 185 1.1 leo root->ar_parts[j].ap_id[k] = 186 1.1 leo ptable->parts[i].id[k]; 187 1.1 leo #ifdef DEBUG 188 1.1 leo printf ("%c", root->ar_parts[j].ap_id[k]); 189 1.1 leo #endif 190 1.1 leo } 191 1.1 leo root->ar_parts[j].ap_st = ptable->parts[i].start - 192 1.1 leo rsec; 193 1.1 leo root->ar_parts[j].ap_size = ptable->parts[i].size; 194 1.1 leo #ifdef DEBUG 195 1.1 leo printf ("/%u/%u\n", root->ar_parts[j].ap_st, 196 1.1 leo root->ar_parts[j].ap_size); 197 1.1 leo #endif 198 1.1 leo j++; 199 1.1 leo if (i < ptable->nparts - 1) { 200 1.1 leo /* Need an XGM? */ 201 1.1 leo if (ptable->parts[i].root != ptable->parts[i+1].root && 202 1.1 leo ptable->parts[i+1].root != 0) { 203 1.1 leo root->ar_parts[j].ap_flg = 0x01; 204 1.1 leo root->ar_parts[j].ap_id[0] = 'X'; 205 1.1 leo root->ar_parts[j].ap_id[1] = 'G'; 206 1.1 leo root->ar_parts[j].ap_id[2] = 'M'; 207 1.1 leo root->ar_parts[j].ap_st = 208 1.1 leo ptable->parts[i+1].root - xgmsec; 209 1.1 leo root->ar_parts[j].ap_size = 210 1.1 leo ptable->parts[i+1].size + 1; 211 1.1 leo #ifdef DEBUG 212 1.1 leo printf (" Partition %d - XGM/%u/%u\n", j, 213 1.1 leo root->ar_parts[j].ap_st, 214 1.1 leo root->ar_parts[j].ap_size); 215 1.1 leo #endif 216 1.1 leo } 217 1.1 leo if (ptable->parts[i].root == ptable->parts[i+1].root) { 218 1.1 leo /* Next partition has same auxiliary root */ 219 1.1 leo #ifdef DEBUG 220 1.1 leo printf (" Partition %d - ", j); 221 1.1 leo #endif 222 1.1 leo root->ar_parts[j].ap_flg = 0x01; 223 1.1 leo for (k = 0; k < 3; k++) { 224 1.1 leo root->ar_parts[j].ap_id[k] = 225 1.1 leo ptable->parts[i+1].id[k]; 226 1.1 leo #ifdef DEBUG 227 1.1 leo printf ("%c", root->ar_parts[j].ap_id[k]); 228 1.1 leo #endif 229 1.1 leo } 230 1.1 leo root->ar_parts[j].ap_st = 231 1.1 leo ptable->parts[i+1].start - rsec; 232 1.1 leo root->ar_parts[j].ap_size = 233 1.1 leo ptable->parts[i+1].size; 234 1.1 leo #ifdef DEBUG 235 1.1 leo printf ("/%u/%u\n", root->ar_parts[j].ap_st, 236 1.1 leo root->ar_parts[j].ap_size); 237 1.1 leo #endif 238 1.1 leo i++; 239 1.1 leo } 240 1.1 leo j++; 241 1.1 leo } 242 1.1 leo 243 1.1 leo if (!disk_write (fd, rsec, 1, root)) { 244 1.1 leo close (fd); 245 1.1 leo free (root); 246 1.1 leo return (-1); 247 1.1 leo } 248 1.1 leo 249 1.1 leo /* 250 1.1 leo * Note first netbsd partition for invalidate_netbsd_label(). 251 1.1 leo */ 252 1.1 leo if (!nbdsec && AHDI_MKPID (ptable->parts[i].id[0], 253 1.1 leo ptable->parts[i].id[1], ptable->parts[i].id[2]) 254 1.1 leo == AHDI_PID_NBD) { 255 1.1 leo nbdsec = ptable->parts[i].start; 256 1.1 leo } 257 1.1 leo } 258 1.1 leo 259 1.1 leo free (root); 260 1.1 leo 261 1.1 leo if (!(flags & AHDI_KEEP_BSL) && !write_bsl (fd)) { 262 1.1 leo close (fd); 263 1.1 leo return (-1); 264 1.1 leo } 265 1.1 leo 266 1.1 leo if (!(flags & AHDI_KEEP_NBDA) && !invalidate_netbsd_label(fd, nbdsec)) { 267 1.1 leo close (fd); 268 1.1 leo return (-1); 269 1.1 leo } 270 1.1 leo 271 1.1 leo #ifdef DEBUG 272 1.1 leo printf ("Forcing disk label re-read\n"); 273 1.1 leo #endif 274 1.1 leo keep = 0; 275 1.1 leo if (ioctl (fd, DIOCKLABEL, &keep) < 0) { 276 1.1 leo close (fd); 277 1.1 leo return (-1); 278 1.1 leo } 279 1.1 leo 280 1.1 leo close (fd); 281 1.1 leo return (1); 282 1.1 leo } 283 1.1 leo 284 1.1 leo /* 285 1.1 leo * Write a bad sector list (empty). 286 1.1 leo */ 287 1.1 leo int 288 1.6 dsl write_bsl (int fd) 289 1.1 leo { 290 1.1 leo u_int8_t *bsl; 291 1.1 leo 292 1.1 leo if ((bsl = malloc (sizeof (u_int8_t) * BSL_SIZE * DEV_BSIZE)) == NULL) 293 1.1 leo return (0); 294 1.1 leo bzero ((void *) bsl, sizeof (u_int8_t) * DEV_BSIZE); 295 1.1 leo 296 1.1 leo #ifdef DEBUG 297 1.1 leo printf ("Writing bad sector list\n"); 298 1.1 leo #endif 299 1.1 leo bsl[3] = BSL_MAGIC; 300 1.1 leo if (!disk_write (fd, (u_int) BSL_OFFSET, (u_int) BSL_SIZE, bsl)) { 301 1.1 leo free (bsl); 302 1.1 leo return (0); 303 1.1 leo } 304 1.1 leo free (bsl); 305 1.1 leo return (1); 306 1.1 leo } 307 1.1 leo 308 1.1 leo /* 309 1.1 leo * Invalidate any previous AHDI/NBDA disklabel. 310 1.1 leo * Otherwise this make take precedence when we next open the disk. 311 1.1 leo */ 312 1.1 leo int 313 1.6 dsl invalidate_netbsd_label (int fd, u_int32_t nbdsec) 314 1.1 leo { 315 1.1 leo struct bootblock *bb; 316 1.1 leo u_int nsec; 317 1.1 leo 318 1.1 leo nsec = (BBMINSIZE + (DEV_BSIZE - 1)) / DEV_BSIZE; 319 1.1 leo 320 1.1 leo if ((bb = disk_read (fd, nbdsec, nsec)) == NULL) { 321 1.1 leo return (0); 322 1.1 leo } 323 1.1 leo 324 1.1 leo if (bb->bb_magic == NBDAMAGIC || bb->bb_magic == AHDIMAGIC) { 325 1.1 leo bb->bb_magic = bb->bb_magic & 0xffffff00; 326 1.1 leo bb->bb_magic = bb->bb_magic | 0x5f; 327 1.1 leo 328 1.1 leo #ifdef DEBUG 329 1.1 leo printf ("Invalidating old NBDA/AHDI label (sector %u)\n", 330 1.1 leo nbdsec); 331 1.1 leo #endif 332 1.1 leo if (!disk_write (fd, nbdsec, nsec, bb)) { 333 1.1 leo free (bb); 334 1.1 leo return (0); 335 1.1 leo } 336 1.1 leo } 337 1.1 leo 338 1.1 leo free (bb); 339 1.1 leo return (1); 340 1.1 leo } 341 1.1 leo 342 1.1 leo int 343 1.1 leo disk_write (fd, start, count, buf) 344 1.1 leo int fd; 345 1.1 leo u_int start, 346 1.1 leo count; 347 1.1 leo void *buf; 348 1.1 leo { 349 1.1 leo off_t offset; 350 1.1 leo size_t size; 351 1.1 leo 352 1.1 leo size = count * DEV_BSIZE; 353 1.1 leo offset = start * DEV_BSIZE; 354 1.1 leo 355 1.1 leo if (lseek (fd, offset, SEEK_SET) != offset) 356 1.1 leo return (0); 357 1.1 leo if (write (fd, buf, size) != size) 358 1.1 leo return (0); 359 1.1 leo return (1); 360 1.1 leo } 361