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 60 static 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 */ 72 const char * 73 readdisklabel(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 */ 130 const char * 131 compat_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 printf("label: %x\n",dlp->magic); 161 msg = ((msg != NULL) ? msg: "no disk label"); 162 goto done; 163 } 164 165 lp->d_magic = DEC_LABEL_MAGIC; 166 lp->d_npartitions = 0; 167 strncpy(lp->d_packname, "Ultrix label", 16); 168 lp->d_rpm = 3600; 169 lp->d_interleave = 1; 170 lp->d_flags = 0; 171 lp->d_bbsize = BBSIZE; 172 lp->d_sbsize = 8192; 173 for (part = 0; 174 part <((MAXPARTITIONS<DEC_NUM_DISK_PARTS) ? 175 MAXPARTITIONS : DEC_NUM_DISK_PARTS); 176 part++) { 177 lp->d_partitions[part].p_size = dlp->map[part].num_blocks; 178 lp->d_partitions[part].p_offset = dlp->map[part].start_block; 179 lp->d_partitions[part].p_fsize = 1024; 180 lp->d_partitions[part].p_fstype = 181 (part==1) ? FS_SWAP : FS_BSDFFS; 182 lp->d_npartitions += 1; 183 184 #ifdef DIAGNOSTIC 185 printf(" Ultrix label rz%d%c: start %d len %d\n", 186 DISKUNIT(dev), "abcdefgh"[part], 187 lp->d_partitions[part].p_offset, 188 lp->d_partitions[part].p_size); 189 #endif 190 } 191 break; 192 } 193 194 done: 195 brelse(bp, 0); 196 return (msg); 197 } 198 #endif /* COMPAT_ULTRIX */ 199 200 /* 201 * Check new disk label for sensibility 202 * before setting it. 203 */ 204 int 205 setdisklabel(struct disklabel *olp, struct disklabel *nlp, 206 u_long openmask, struct cpu_disklabel *osdep) 207 { 208 int i; 209 struct partition *opp, *npp; 210 211 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || 212 dkcksum(nlp) != 0) 213 return (EINVAL); 214 while ((i = ffs(openmask)) != 0) { 215 i--; 216 openmask &= ~(1 << i); 217 if (nlp->d_npartitions <= i) 218 return (EBUSY); 219 opp = &olp->d_partitions[i]; 220 npp = &nlp->d_partitions[i]; 221 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) 222 return (EBUSY); 223 /* 224 * Copy internally-set partition information 225 * if new label doesn't include it. XXX 226 */ 227 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { 228 npp->p_fstype = opp->p_fstype; 229 npp->p_fsize = opp->p_fsize; 230 npp->p_frag = opp->p_frag; 231 npp->p_cpg = opp->p_cpg; 232 } 233 } 234 nlp->d_checksum = 0; 235 nlp->d_checksum = dkcksum(nlp); 236 *olp = *nlp; 237 return (0); 238 } 239 240 /* 241 * Write disk label back to device after modification. 242 * Always allow writing of disk label; even if the disk is unlabeled. 243 */ 244 int 245 writedisklabel(dev_t dev, void (*strat)(struct buf *), 246 struct disklabel *lp, struct cpu_disklabel *osdep) 247 { 248 struct buf *bp; 249 struct disklabel *dlp; 250 int error = 0; 251 252 bp = geteblk((int)lp->d_secsize); 253 bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART); 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))) 259 goto done; 260 dlp = (struct disklabel *)((char *)bp->b_data + LABELOFFSET); 261 memcpy(dlp, lp, sizeof(struct disklabel)); 262 bp->b_oflags &= ~(BO_DONE); 263 bp->b_flags &= ~(B_READ); 264 bp->b_flags |= B_WRITE; 265 (*strat)(bp); 266 error = biowait(bp); 267 268 done: 269 brelse(bp, 0); 270 return (error); 271 } 272 273 /* 274 * Print out the name of the device; ex. TK50, RA80. DEC uses a common 275 * disk type encoding scheme for most of its disks. 276 */ 277 void 278 disk_printtype(int unit, int type) 279 { 280 printf(" drive %d: %c%c", unit, (int)MSCP_MID_CHAR(2, type), 281 (int)MSCP_MID_CHAR(1, type)); 282 if (MSCP_MID_ECH(0, type)) 283 printf("%c", (int)MSCP_MID_CHAR(0, type)); 284 printf("%d\n", MSCP_MID_NUM(type)); 285 } 286 287 /* 288 * Be sure that the pages we want to do DMA to is actually there 289 * by faking page-faults if necessary. If given a map-register address, 290 * also map it in. 291 */ 292 void 293 disk_reallymapin(struct buf *bp, struct pte *map, int reg, int flag) 294 { 295 struct proc *p; 296 volatile pt_entry_t *io; 297 pt_entry_t *pte; 298 int pfnum, npf, o; 299 void *addr; 300 301 o = (int)bp->b_data & VAX_PGOFSET; 302 npf = vax_btoc(bp->b_bcount + o) + 1; 303 addr = bp->b_data; 304 p = bp->b_proc; 305 306 /* 307 * Get a pointer to the pte pointing out the first virtual address. 308 * Use different ways in kernel and user space. 309 */ 310 if ((bp->b_flags & B_PHYS) == 0) { 311 pte = kvtopte(addr); 312 if (p == 0) 313 p = &proc0; 314 } else { 315 long xaddr = (long)addr; 316 if (xaddr & 0x40000000) 317 pte = &p->p_vmspace->vm_map.pmap->pm_p1br[xaddr & 318 ~0x40000000]; 319 else 320 pte = &p->p_vmspace->vm_map.pmap->pm_p0br[xaddr]; 321 } 322 323 if (map) { 324 io = &map[reg]; 325 while (--npf > 0) { 326 pfnum = pte->pg_pfn; 327 if (pfnum == 0) 328 panic("mapin zero entry"); 329 pte++; 330 *(volatile int *)io++ = pfnum | flag; 331 } 332 *(volatile int *)io = 0; 333 } 334 } 335