1 /* $NetBSD: disksubr.c,v 1.24 2019/04/03 22:10:51 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Christopher Sekiya 5 * Copyright (c) 2001 Wayne Knowles 6 * Copyright (c) 2000 Soren S. Jorvang 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the 20 * NetBSD Project. See http://www.NetBSD.org/ for 21 * information about NetBSD. 22 * 4. The name of the author may not be used to endorse or promote products 23 * derived from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.24 2019/04/03 22:10:51 christos Exp $"); 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/buf.h> 43 #include <sys/disklabel.h> 44 #include <sys/disk.h> 45 #include <ufs/ufs/dinode.h> 46 #include <ufs/ffs/fs.h> 47 48 #include <machine/disklabel.h> 49 50 static int disklabel_bsd_to_sgimips(struct disklabel *lp, 51 struct sgi_boot_block *vh); 52 static const char *disklabel_sgimips_to_bsd(struct sgi_boot_block *vh, 53 struct disklabel *lp); 54 55 int mipsvh_cksum(struct sgi_boot_block *vhp); 56 57 #define LABELSIZE(lp) ((char *)&lp->d_partitions[lp->d_npartitions] - \ 58 (char *)lp) 59 60 61 /* 62 * Attempt to read a disk label from a device using the indicated 63 * strategy routine. The label must be partly set up before this: 64 * secpercyl, secsize and anything required for a block i/o read 65 * operation in the driver's strategy/start routines must be 66 * filled in before calling us. 67 * 68 * Return buffer for use in signalling errors if requested. 69 * 70 * Returns null on success and an error string on failure. 71 */ 72 73 const char * 74 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp) 75 { 76 struct buf *bp; 77 struct disklabel *dlp; 78 struct sgi_boot_block *slp; 79 int err; 80 81 /* Minimal requirements for archetypal disk label. */ 82 if (lp->d_secsize == 0) 83 lp->d_secsize = DEV_BSIZE; 84 if (lp->d_secperunit == 0) 85 lp->d_secperunit = 0x1fffffff; 86 87 /* Obtain buffer to probe drive with. */ 88 bp = geteblk((int)lp->d_secsize); 89 90 bp->b_dev = dev; 91 bp->b_blkno = LABELSECTOR; 92 bp->b_bcount = lp->d_secsize; 93 bp->b_flags |= B_READ; 94 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl; 95 (*strat)(bp); 96 err = biowait(bp); 97 brelse(bp, 0); 98 99 if (err) 100 return "error reading disklabel"; 101 102 /* Check for NetBSD label in second sector */ 103 dlp = (struct disklabel *)((char *)bp->b_data + LABELOFFSET); 104 if (dlp->d_magic == DISKMAGIC) 105 if (!dkcksum(dlp)) { 106 memcpy(lp, dlp, LABELSIZE(dlp)); 107 return NULL; /* NetBSD label found */ 108 } 109 110 bp = geteblk((int)lp->d_secsize); 111 bp->b_dev = dev; 112 bp->b_blkno = 0; 113 bp->b_bcount = lp->d_secsize; 114 bp->b_flags |= B_READ; 115 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl; 116 (*strat)(bp); 117 err = biowait(bp); 118 brelse(bp, 0); 119 120 if (err) 121 return "error reading volume header"; 122 123 /* Check for a SGI label. */ 124 slp = (struct sgi_boot_block *)bp->b_data; 125 if (be32toh(slp->magic) != SGI_BOOT_BLOCK_MAGIC) 126 return "no disk label"; 127 128 return disklabel_sgimips_to_bsd(slp, lp); 129 } 130 131 #define dkpart(dev) (minor(dev) & 07) 132 #define dkminor(unit, part) (((unit) << 3) | (part)) 133 134 int 135 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp) 136 { 137 struct buf *bp; 138 int labelpart; 139 int error; 140 141 labelpart = dkpart(dev); 142 if (lp->d_partitions[labelpart].p_offset != 0) { 143 if (lp->d_partitions[0].p_offset != 0) 144 return (EXDEV); /* not quite right */ 145 labelpart = 0; 146 } 147 148 /* Read sgimips volume header before merging NetBSD partition info */ 149 bp = geteblk((int)lp->d_secsize); 150 151 bp->b_dev = dev; 152 bp->b_blkno = 0; 153 bp->b_bcount = lp->d_secsize; 154 bp->b_flags |= B_READ; 155 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl; 156 (*strat)(bp); 157 158 if((error = biowait(bp)) != 0) 159 goto ioerror; 160 161 if ((error = disklabel_bsd_to_sgimips(lp, (void *)bp->b_data)) != 0) 162 goto ioerror; 163 164 /* Write sgimips label to first sector */ 165 bp->b_oflags &= ~(BO_DONE); 166 bp->b_flags &= ~(B_READ); 167 bp->b_flags |= B_WRITE; 168 (*strat)(bp); 169 if ((error = biowait(bp)) != 0) 170 goto ioerror; 171 172 /* Write NetBSD disk label to second sector */ 173 memset(bp->b_data, 0, lp->d_secsize); 174 memcpy(bp->b_data, lp, sizeof(*lp)); 175 bp->b_blkno = LABELSECTOR; 176 bp->b_bcount = lp->d_secsize; 177 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl; 178 bp->b_oflags &= ~(BO_DONE); 179 bp->b_flags &= ~(B_READ); 180 bp->b_flags |= B_WRITE; 181 (*strat)(bp); 182 error = biowait(bp); 183 184 ioerror: 185 brelse(bp, 0); 186 return error; 187 } 188 189 struct partitionmap { 190 int mips_part; /* sgimips partition number */ 191 int mips_type; /* sgimips partition type */ 192 int bsd_part; /* BSD partition number */ 193 int bsd_type; /* BSD partition type */ 194 }; 195 196 struct partitionmap partition_map[] = { 197 /* slice sgimips type BSD BSD Type */ 198 {0, SGI_PTYPE_BSD, 0, FS_BSDFFS}, 199 {1, SGI_PTYPE_RAW, 1, FS_SWAP}, 200 {2, SGI_PTYPE_BSD, 10, FS_BSDFFS}, 201 {3, SGI_PTYPE_BSD, 3, FS_BSDFFS}, 202 {4, SGI_PTYPE_BSD, 4, FS_BSDFFS}, 203 {5, SGI_PTYPE_BSD, 5, FS_BSDFFS}, 204 {6, SGI_PTYPE_BSD, 6, FS_BSDFFS}, 205 {7, SGI_PTYPE_BSD, 7, FS_BSDFFS}, 206 {8, SGI_PTYPE_VOLHDR, 8, FS_OTHER}, 207 {9, SGI_PTYPE_BSD, 9, FS_BSDFFS}, 208 {10, SGI_PTYPE_VOLUME, 2, FS_OTHER}, 209 {11, SGI_PTYPE_BSD, 11, FS_BSDFFS}, 210 {12, SGI_PTYPE_BSD, 12, FS_BSDFFS}, 211 {13, SGI_PTYPE_BSD, 13, FS_BSDFFS}, 212 {14, SGI_PTYPE_BSD, 14, FS_BSDFFS}, 213 {15, SGI_PTYPE_BSD, 15, FS_BSDFFS} 214 }; 215 216 #define NPARTMAP (sizeof(partition_map)/sizeof(struct partitionmap)) 217 218 /* 219 * Convert a sgimips disk label into a NetBSD disk label. 220 * 221 * Returns NULL on success, otherwise an error string 222 */ 223 static const char * 224 disklabel_sgimips_to_bsd(struct sgi_boot_block *vh, struct disklabel *lp) 225 { 226 int i, bp, mp; 227 struct partition *lpp; 228 if (mipsvh_cksum(vh)) 229 return ("sgimips disk label corrupted"); 230 231 #if 0 /* ARCS ignores dp_secbytes and it may be wrong; use default instead */ 232 lp->d_secsize = vh->dp.dp_secbytes; 233 #endif 234 lp->d_nsectors = vh->dp.dp_secs; 235 lp->d_ntracks = vh->dp.dp_trks0; 236 lp->d_ncylinders = vh->dp.dp_cyls; 237 lp->d_interleave = vh->dp.dp_interleave; 238 239 240 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 241 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 242 243 lp->d_bbsize = BBSIZE; 244 lp->d_sbsize = SBLOCKSIZE; 245 lp->d_npartitions = MAXPARTITIONS; 246 247 for (i = 0; i < 16; i++) { 248 mp = partition_map[i].mips_part; 249 bp = partition_map[i].bsd_part; 250 251 lpp = &lp->d_partitions[bp]; 252 lpp->p_offset = vh->partitions[mp].first; 253 /* XXX ARCS ignores dp_secbytes on calculating offsets */ 254 if (lp->d_secsize > DEV_BSIZE) 255 lpp->p_offset /= lp->d_secsize / DEV_BSIZE; 256 lpp->p_size = vh->partitions[mp].blocks; 257 lpp->p_fstype = partition_map[i].bsd_type; 258 if (lpp->p_fstype == FS_BSDFFS) { 259 lpp->p_fsize = 1024; 260 lpp->p_frag = 8; 261 lpp->p_cpg = 16; 262 } 263 } 264 return NULL; 265 } 266 267 268 /* 269 * Convert a NetBSD disk label into a sgimips disk label. 270 * 271 * Returns NULL on success, otherwise an error string 272 */ 273 static int 274 disklabel_bsd_to_sgimips(struct disklabel *lp, struct sgi_boot_block *vh) 275 { 276 int i, bp, mp; 277 struct partition *lpp; 278 279 if (vh->magic != SGI_BOOT_BLOCK_MAGIC || mipsvh_cksum(vh) != 0) { 280 memset((void *)vh, 0, sizeof *vh); 281 vh->magic = SGI_BOOT_BLOCK_MAGIC; 282 vh->root = 0; /* a*/ 283 vh->swap = 1; /* b*/ 284 } 285 286 strcpy(vh->bootfile, "/netbsd"); 287 vh->dp.dp_skew = lp->d_trackskew; 288 vh->dp.dp_gap1 = 1; /* XXX */ 289 vh->dp.dp_gap2 = 1; /* XXX */ 290 vh->dp.dp_cyls = lp->d_ncylinders; 291 vh->dp.dp_shd0 = 0; 292 vh->dp.dp_trks0 = lp->d_ntracks; 293 vh->dp.dp_secs = lp->d_nsectors; 294 #if 0 /* ARCS ignores dp_secbytes; leave it default */ 295 vh->dp.dp_secbytes = lp->d_secsize; 296 #else 297 vh->dp.dp_secbytes = SGI_BOOT_BLOCK_BLOCKSIZE; 298 #endif 299 vh->dp.dp_interleave = lp->d_interleave; 300 vh->dp.dp_nretries = 22; 301 302 for (i = 0; i < 16; i++) { 303 mp = partition_map[i].mips_part; 304 bp = partition_map[i].bsd_part; 305 306 lpp = &lp->d_partitions[bp]; 307 vh->partitions[mp].first = lpp->p_offset; 308 /* XXX ARCS ignores dp_secbytes on calculating offsets */ 309 if (lp->d_secsize > SGI_BOOT_BLOCK_BLOCKSIZE) 310 vh->partitions[mp].first *= 311 lp->d_secsize / SGI_BOOT_BLOCK_BLOCKSIZE; 312 vh->partitions[mp].blocks = lpp->p_size; 313 vh->partitions[mp].type = partition_map[i].mips_type; 314 } 315 316 /* 317 * Create a fake partition for bootstrap code (or SASH) 318 */ 319 vh->partitions[8].first = 0; 320 vh->partitions[8].blocks = vh->partitions[vh->root].first + 321 BBSIZE / vh->dp.dp_secbytes; 322 vh->partitions[8].type = SGI_PTYPE_VOLHDR; 323 324 vh->checksum = 0; 325 vh->checksum = -mipsvh_cksum(vh); 326 return 0; 327 } 328 329 /* 330 * Compute checksum for MIPS disk volume header 331 * 332 * Mips volume header checksum is the 32bit 2's complement sum 333 * of the entire volume header structure 334 */ 335 int 336 mipsvh_cksum(struct sgi_boot_block *vhp) 337 { 338 int i, *ptr; 339 int cksum = 0; 340 341 ptr = (int *)vhp; 342 i = sizeof(*vhp) / sizeof(*ptr); 343 while (i--) 344 cksum += *ptr++; 345 return cksum; 346 } 347 348