1/* $NetBSD: disksubr.c,v 1.52 2010/12/14 23:44:49 matt 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.52 2010/12/14 23:44:49 matt 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/cpu.h> 43#include <sys/dkbad.h> 44#include <sys/disklabel.h> 45#include <sys/disk.h> 46#include <sys/syslog.h> 47#include <sys/proc.h> 48 49#include <uvm/uvm_extern.h> 50 51#include <machine/macros.h> 52 53#include <dev/mscp/mscp.h> /* For disk encoding scheme */ 54 55#ifdef COMPAT_ULTRIX 56#include <dev/dec/dec_boot.h> 57#include <ufs/ufs/dinode.h> /* XXX for fs.h */ 58#include <ufs/ffs/fs.h> /* XXX for BBSIZE & SBSIZE */ 59 60static const char *compat_label(dev_t dev, void (*strat)(struct buf *bp), 61 struct disklabel *lp, struct cpu_disklabel *osdep); 62#endif /* COMPAT_ULTRIX */ 63 64/* 65 * Attempt to read a disk label from a device 66 * using the indicated strategy routine. 67 * The label must be partly set up before this: 68 * secpercyl and anything required in the strategy routine 69 * (e.g., sector size) must be filled in before calling us. 70 * Returns null on success and an error string on failure. 71 */ 72const char * 73readdisklabel(dev_t dev, void (*strat)(struct buf *), 74 struct disklabel *lp, struct cpu_disklabel *osdep) 75{ 76 struct buf *bp; 77 struct disklabel *dlp; 78 const char *msg = NULL; 79 80 if (lp->d_npartitions == 0) { /* Assume no label */ 81 lp->d_secperunit = 0x1fffffff; 82 lp->d_npartitions = 3; 83 lp->d_partitions[2].p_size = 0x1fffffff; 84 lp->d_partitions[2].p_offset = 0; 85 } 86 87 bp = geteblk((int)lp->d_secsize); 88 bp->b_dev = dev; 89 bp->b_blkno = LABELSECTOR; 90 bp->b_bcount = lp->d_secsize; 91 bp->b_flags |= B_READ; 92 bp->b_cylinder = LABELSECTOR / lp->d_secpercyl; 93 (*strat)(bp); 94 if (biowait(bp)) { 95 msg = "I/O error"; 96 } else { 97 dlp = (struct disklabel *)((char *)bp->b_data + LABELOFFSET); 98 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { 99 msg = "no disk label"; 100 } else if (dlp->d_npartitions > MAXPARTITIONS || 101 dkcksum(dlp) != 0) 102 msg = "disk label corrupted"; 103 else { 104 *lp = *dlp; 105 } 106 } 107 brelse(bp, 0); 108 109#ifdef COMPAT_ULTRIX 110 /* 111 * If no NetBSD label was found, check for an Ultrix label and 112 * construct tne incore label from the Ultrix partition information. 113 */ 114 if (msg != NULL) { 115 msg = compat_label(dev, strat, lp, osdep); 116 if (msg == NULL) { 117 printf("WARNING: using Ultrix partition information\n"); 118 /* set geometry? */ 119 } 120 } 121#endif 122 return (msg); 123} 124 125#ifdef COMPAT_ULTRIX 126/* 127 * Given a buffer bp, try and interpret it as an Ultrix disk label, 128 * putting the partition info into a native NetBSD label 129 */ 130const char * 131compat_label(dev_t dev, void (*strat)(struct buf *bp), struct disklabel *lp, 132 struct cpu_disklabel *osdep) 133{ 134 dec_disklabel *dlp; 135 struct buf *bp = NULL; 136 const char *msg = NULL; 137 uint8_t *dp; 138 139 bp = geteblk((int)lp->d_secsize); 140 dp = bp->b_data; 141 bp->b_dev = dev; 142 bp->b_blkno = DEC_LABEL_SECTOR; 143 bp->b_bcount = lp->d_secsize; 144 bp->b_flags |= B_READ; 145 bp->b_cylinder = DEC_LABEL_SECTOR / lp->d_secpercyl; 146 (*strat)(bp); 147 148 if (biowait(bp)) { 149 msg = "I/O error"; 150 goto done; 151 } 152 153 for (dlp = (dec_disklabel *)dp; 154 dlp <= (dec_disklabel *)(dp+DEV_BSIZE-sizeof(*dlp)); 155 dlp = (dec_disklabel *)((char *)dlp + sizeof(long))) { 156 157 int part; 158 159 if (dlp->magic != DEC_LABEL_MAGIC) { 160 if (dlp->magic != 0) 161 printf("label: %x\n",dlp->magic); 162 msg = ((msg != NULL) ? msg: "no disk label"); 163 goto done; 164 } 165 166 lp->d_magic = DEC_LABEL_MAGIC; 167 lp->d_npartitions = 0; 168 strncpy(lp->d_packname, "Ultrix label", 16); 169 lp->d_rpm = 3600; 170 lp->d_interleave = 1; 171 lp->d_flags = 0; 172 lp->d_bbsize = BBSIZE; 173 lp->d_sbsize = 8192; 174 for (part = 0; 175 part <((MAXPARTITIONS<DEC_NUM_DISK_PARTS) ? 176 MAXPARTITIONS : DEC_NUM_DISK_PARTS); 177 part++) { 178 lp->d_partitions[part].p_size = dlp->map[part].num_blocks; 179 lp->d_partitions[part].p_offset = dlp->map[part].start_block; 180 lp->d_partitions[part].p_fsize = 1024; 181 lp->d_partitions[part].p_fstype = 182 (part==1) ? FS_SWAP : FS_BSDFFS; 183 lp->d_npartitions += 1; 184 185#ifdef DIAGNOSTIC 186 printf(" Ultrix label rz%d%c: start %d len %d\n", 187 DISKUNIT(dev), "abcdefgh"[part], 188 lp->d_partitions[part].p_offset, 189 lp->d_partitions[part].p_size); 190#endif 191 } 192 break; 193 } 194 195done: 196 brelse(bp, 0); 197 return (msg); 198} 199#endif /* COMPAT_ULTRIX */ 200 201/* 202 * Check new disk label for sensibility 203 * before setting it. 204 */ 205int 206setdisklabel(struct disklabel *olp, struct disklabel *nlp, 207 u_long openmask, struct cpu_disklabel *osdep) 208{ 209 int i; 210 struct partition *opp, *npp; 211 212 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || 213 dkcksum(nlp) != 0) 214 return (EINVAL); 215 while ((i = ffs(openmask)) != 0) { 216 i--; 217 openmask &= ~(1 << i); 218 if (nlp->d_npartitions <= i) 219 return (EBUSY); 220 opp = &olp->d_partitions[i]; 221 npp = &nlp->d_partitions[i]; 222 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) 223 return (EBUSY); 224 /* 225 * Copy internally-set partition information 226 * if new label doesn't include it. XXX 227 */ 228 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { 229 npp->p_fstype = opp->p_fstype; 230 npp->p_fsize = opp->p_fsize; 231 npp->p_frag = opp->p_frag; 232 npp->p_cpg = opp->p_cpg; 233 } 234 } 235 nlp->d_checksum = 0; 236 nlp->d_checksum = dkcksum(nlp); 237 *olp = *nlp; 238 return (0); 239} 240 241/* 242 * Write disk label back to device after modification. 243 * Always allow writing of disk label; even if the disk is unlabeled. 244 */ 245int 246writedisklabel(dev_t dev, void (*strat)(struct buf *), 247 struct disklabel *lp, struct cpu_disklabel *osdep) 248{ 249 struct buf *bp; 250 struct disklabel *dlp; 251 int error = 0; 252 253 bp = geteblk((int)lp->d_secsize); 254 bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART); 255 bp->b_blkno = LABELSECTOR; 256 bp->b_bcount = lp->d_secsize; 257 bp->b_flags |= B_READ; 258 (*strat)(bp); 259 if ((error = biowait(bp))) 260 goto done; 261 dlp = (struct disklabel *)((char *)bp->b_data + LABELOFFSET); 262 memcpy(dlp, lp, sizeof(struct disklabel)); 263 bp->b_oflags &= ~(BO_DONE); 264 bp->b_flags &= ~(B_READ); 265 bp->b_flags |= B_WRITE; 266 (*strat)(bp); 267 error = biowait(bp); 268 269done: 270 brelse(bp, 0); 271 return (error); 272} 273 274/* 275 * Print out the name of the device; ex. TK50, RA80. DEC uses a common 276 * disk type encoding scheme for most of its disks. 277 */ 278void 279disk_printtype(int unit, int type) 280{ 281 printf(" drive %d: %c%c", unit, (int)MSCP_MID_CHAR(2, type), 282 (int)MSCP_MID_CHAR(1, type)); 283 if (MSCP_MID_ECH(0, type)) 284 printf("%c", (int)MSCP_MID_CHAR(0, type)); 285 printf("%d\n", MSCP_MID_NUM(type)); 286} 287 288/* 289 * Be sure that the pages we want to do DMA to is actually there 290 * by faking page-faults if necessary. If given a map-register address, 291 * also map it in. 292 */ 293void 294disk_reallymapin(struct buf *bp, struct pte *map, int reg, int flag) 295{ 296 struct proc *p; 297 volatile pt_entry_t *io; 298 pt_entry_t *pte; 299 int pfnum, npf, o; 300 void *addr; 301 302 o = (int)bp->b_data & VAX_PGOFSET; 303 npf = vax_btoc(bp->b_bcount + o) + 1; 304 addr = bp->b_data; 305 p = bp->b_proc; 306 307 /* 308 * Get a pointer to the pte pointing out the first virtual address. 309 * Use different ways in kernel and user space. 310 */ 311 if ((bp->b_flags & B_PHYS) == 0) { 312 pte = kvtopte(addr); 313 if (p == 0) 314 p = &proc0; 315 } else { 316 long xaddr = (long)addr; 317 if (xaddr & 0x40000000) 318 pte = &p->p_vmspace->vm_map.pmap->pm_p1br[xaddr & 319 ~0x40000000]; 320 else 321 pte = &p->p_vmspace->vm_map.pmap->pm_p0br[xaddr]; 322 } 323 324 if (map) { 325 io = &map[reg]; 326 while (--npf > 0) { 327 pfnum = pte->pg_pfn; 328 if (pfnum == 0) 329 panic("mapin zero entry"); 330 pte++; 331 *(volatile int *)io++ = pfnum | flag; 332 } 333 *(volatile int *)io = 0; 334 } 335} 336