1/* $NetBSD: disksubr.c,v 1.53 2009/07/20 17:05:13 tsutsui Exp $ */ 2 3/* 4 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 32 */ 33 34#include <sys/cdefs.h> 35__KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.53 2009/07/20 17:05:13 tsutsui Exp $"); 36 37#include "opt_compat_ultrix.h" 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/buf.h> 42#include <sys/disk.h> 43#include <sys/disklabel.h> 44 45#include <dev/dec/dec_boot.h> 46#include <ufs/ufs/dinode.h> /* XXX for fs.h */ 47#include <ufs/ffs/fs.h> /* XXX for BBSIZE & SBSIZE */ 48 49const char *compat_label(dev_t dev, void (*strat)(struct buf *bp), 50 struct disklabel *lp, struct cpu_disklabel *osdep); /* XXX */ 51 52/* 53 * Attempt to read a disk label from a device 54 * using the indicated strategy routine. 55 * The label must be partly set up before this: 56 * secpercyl and anything required in the strategy routine 57 * (e.g., sector size) must be filled in before calling us. 58 * Returns null on success and an error string on failure. 59 */ 60const char * 61readdisklabel(dev_t dev, void (*strat)(struct buf *bp), struct disklabel *lp, 62 struct cpu_disklabel *osdep) 63{ 64 struct buf *bp; 65 struct disklabel *dlp; 66 const char *msg = NULL; 67 68 if (lp->d_secperunit == 0) 69 lp->d_secperunit = 0x1fffffff; 70 lp->d_npartitions = 1; 71 if (lp->d_partitions[0].p_size == 0) 72 lp->d_partitions[0].p_size = 0x1fffffff; 73 lp->d_partitions[0].p_offset = 0; 74 75 bp = geteblk((int)lp->d_secsize); 76 bp->b_dev = dev; 77 bp->b_blkno = LABELSECTOR; 78 bp->b_bcount = lp->d_secsize; 79 bp->b_flags |= B_READ; 80 bp->b_cylinder = LABELSECTOR / lp->d_secpercyl; 81 (*strat)(bp); 82 if (biowait(bp)) { 83 msg = "I/O error"; 84 } else for (dlp = (struct disklabel *)bp->b_data; 85 dlp <= (struct disklabel *) 86 ((char *)bp->b_data + DEV_BSIZE - sizeof(*dlp)); 87 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 88 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { 89 if (msg == NULL) 90 msg = "no disk label"; 91 } else if (dlp->d_npartitions > MAXPARTITIONS || 92 dkcksum(dlp) != 0) 93 msg = "disk label corrupted"; 94 else { 95 *lp = *dlp; 96 msg = NULL; 97 break; 98 } 99 } 100 brelse(bp, 0); 101 /* 102 * If no NetBSD label was found, check for an Ultrix label and 103 * construct tne incore label from the Ultrix partition information. 104 */ 105 if (msg != NULL) { 106 msg = compat_label(dev, strat, lp, osdep); 107 if (msg == NULL) { 108 printf("WARNING: using Ultrix partition information\n"); 109 /* set geometry? */ 110 } 111 } 112/* XXX If no NetBSD label or Ultrix label found, generate default label here */ 113 return msg; 114} 115 116/* 117 * Given a buffer bp, try and interpret it as an Ultrix disk label, 118 * putting the partition info into a native NetBSD label 119 */ 120const char * 121compat_label(dev_t dev, void (*strat)(struct buf *bp), struct disklabel *lp, 122 struct cpu_disklabel *osdep) 123{ 124 dec_disklabel *dlp; 125 struct buf *bp = NULL; 126 const char *msg = NULL; 127 128 bp = geteblk((int)lp->d_secsize); 129 bp->b_dev = dev; 130 bp->b_blkno = DEC_LABEL_SECTOR; 131 bp->b_bcount = lp->d_secsize; 132 bp->b_flags |= B_READ; 133 bp->b_cylinder = DEC_LABEL_SECTOR / lp->d_secpercyl; 134 (*strat)(bp); 135 136 if (biowait(bp)) { 137 msg = "I/O error"; 138 goto done; 139 } 140 141 for (dlp = (dec_disklabel *)bp->b_data; 142 dlp <= (dec_disklabel *) 143 ((char *)bp->b_data + DEV_BSIZE - sizeof(*dlp)); 144 dlp = (dec_disklabel *)((char *)dlp + sizeof(long))) { 145 146 int part; 147 148 if (dlp->magic != DEC_LABEL_MAGIC) { 149 printf("label: %x\n",dlp->magic); 150 msg = ((msg != NULL) ? msg: "no disk label"); 151 goto done; 152 } 153 154#ifdef DIAGNOSTIC 155/*XXX*/ printf("Interpreting Ultrix label\n"); 156#endif 157 158 lp->d_magic = DEC_LABEL_MAGIC; 159 lp->d_npartitions = 0; 160 strncpy(lp->d_packname, "Ultrix label", 16); 161 lp->d_rpm = 3600; 162 lp->d_interleave = 1; 163 lp->d_flags = 0; 164 lp->d_bbsize = BBSIZE; 165 lp->d_sbsize = SBLOCKSIZE; 166 for (part = 0; 167 part <((MAXPARTITIONS<DEC_NUM_DISK_PARTS) ? 168 MAXPARTITIONS : DEC_NUM_DISK_PARTS); 169 part++) { 170 lp->d_partitions[part].p_size = 171 dlp->map[part].num_blocks; 172 lp->d_partitions[part].p_offset = 173 dlp->map[part].start_block; 174 lp->d_partitions[part].p_fsize = 1024; 175 lp->d_partitions[part].p_fstype = 176 (part==1) ? FS_SWAP : FS_BSDFFS; 177 lp->d_npartitions += 1; 178 179#ifdef DIAGNOSTIC 180 printf(" Ultrix label rz%d%c: start %d len %d\n", 181 DISKUNIT(dev), "abcdefgh"[part], 182 lp->d_partitions[part].p_offset, 183 lp->d_partitions[part].p_size); 184#endif 185 } 186 break; 187 } 188 189done: 190 brelse(bp, 0); 191 return msg; 192} 193 194/* 195 * Check new disk label for sensibility 196 * before setting it. 197 */ 198int 199setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask, 200 struct cpu_disklabel *osdep) 201{ 202 int i; 203 struct partition *opp, *npp; 204 205 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || 206 dkcksum(nlp) != 0) 207 return EINVAL; 208 while ((i = ffs(openmask)) != 0) { 209 i--; 210 openmask &= ~(1 << i); 211 if (nlp->d_npartitions <= i) 212 return EBUSY; 213 opp = &olp->d_partitions[i]; 214 npp = &nlp->d_partitions[i]; 215 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) 216 return EBUSY; 217 /* 218 * Copy internally-set partition information 219 * if new label doesn't include it. XXX 220 */ 221 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { 222 npp->p_fstype = opp->p_fstype; 223 npp->p_fsize = opp->p_fsize; 224 npp->p_frag = opp->p_frag; 225 npp->p_cpg = opp->p_cpg; 226 } 227 } 228 nlp->d_checksum = 0; 229 nlp->d_checksum = dkcksum(nlp); 230 *olp = *nlp; 231 return 0; 232} 233 234/* 235 * Write disk label back to device after modification. 236 */ 237int 238writedisklabel(dev_t dev, void (*strat)(struct buf *bp), struct disklabel *lp, 239 struct cpu_disklabel *osdep) 240{ 241 struct buf *bp; 242 struct disklabel *dlp; 243 int labelpart; 244 int error = 0; 245 246 labelpart = DISKPART(dev); 247 if (lp->d_partitions[labelpart].p_offset != 0) { 248 if (lp->d_partitions[0].p_offset != 0) 249 return EXDEV; /* not quite right */ 250 labelpart = 0; 251 } 252 bp = geteblk((int)lp->d_secsize); 253 bp->b_dev = makedev(major(dev), DISKMINOR(DISKUNIT(dev), labelpart)); 254 bp->b_blkno = LABELSECTOR; 255 bp->b_bcount = lp->d_secsize; 256 bp->b_flags |= B_READ; 257 (*strat)(bp); 258 if ((error = biowait(bp)) != 0) 259 goto done; 260 for (dlp = (struct disklabel *)bp->b_data; 261 dlp <= (struct disklabel *) 262 ((char *)bp->b_data + lp->d_secsize - sizeof(*dlp)); 263 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 264 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && 265 dkcksum(dlp) == 0) { 266 *dlp = *lp; 267 bp->b_oflags &= ~(BO_DONE); 268 bp->b_flags &= ~(B_READ); 269 bp->b_flags |= B_WRITE; 270 (*strat)(bp); 271 error = biowait(bp); 272 goto done; 273 } 274 } 275 error = ESRCH; 276done: 277 brelse(bp, 0); 278 return error; 279} 280