1 /* $NetBSD: disksubr.c,v 1.54 2019/04/03 22:10:51 christos 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.54 2019/04/03 22:10:51 christos 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 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 195 done: 196 brelse(bp, 0); 197 return (msg); 198 } 199 #endif /* COMPAT_ULTRIX */ 200 201 /* 202 * Write disk label back to device after modification. 203 * Always allow writing of disk label; even if the disk is unlabeled. 204 */ 205 int 206 writedisklabel(dev_t dev, void (*strat)(struct buf *), 207 struct disklabel *lp, struct cpu_disklabel *osdep) 208 { 209 struct buf *bp; 210 struct disklabel *dlp; 211 int error = 0; 212 213 bp = geteblk((int)lp->d_secsize); 214 bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART); 215 bp->b_blkno = LABELSECTOR; 216 bp->b_bcount = lp->d_secsize; 217 bp->b_flags |= B_READ; 218 (*strat)(bp); 219 if ((error = biowait(bp))) 220 goto done; 221 dlp = (struct disklabel *)((char *)bp->b_data + LABELOFFSET); 222 memcpy(dlp, lp, sizeof(struct disklabel)); 223 bp->b_oflags &= ~(BO_DONE); 224 bp->b_flags &= ~(B_READ); 225 bp->b_flags |= B_WRITE; 226 (*strat)(bp); 227 error = biowait(bp); 228 229 done: 230 brelse(bp, 0); 231 return (error); 232 } 233 234 /* 235 * Print out the name of the device; ex. TK50, RA80. DEC uses a common 236 * disk type encoding scheme for most of its disks. 237 */ 238 void 239 disk_printtype(int unit, int type) 240 { 241 printf(" drive %d: %c%c", unit, (int)MSCP_MID_CHAR(2, type), 242 (int)MSCP_MID_CHAR(1, type)); 243 if (MSCP_MID_ECH(0, type)) 244 printf("%c", (int)MSCP_MID_CHAR(0, type)); 245 printf("%d\n", MSCP_MID_NUM(type)); 246 } 247 248 /* 249 * Be sure that the pages we want to do DMA to is actually there 250 * by faking page-faults if necessary. If given a map-register address, 251 * also map it in. 252 */ 253 void 254 disk_reallymapin(struct buf *bp, struct pte *map, int reg, int flag) 255 { 256 struct proc *p; 257 volatile pt_entry_t *io; 258 pt_entry_t *pte; 259 int pfnum, npf, o; 260 void *addr; 261 262 o = (int)bp->b_data & VAX_PGOFSET; 263 npf = vax_btoc(bp->b_bcount + o) + 1; 264 addr = bp->b_data; 265 p = bp->b_proc; 266 267 /* 268 * Get a pointer to the pte pointing out the first virtual address. 269 * Use different ways in kernel and user space. 270 */ 271 if ((bp->b_flags & B_PHYS) == 0) { 272 pte = kvtopte(addr); 273 if (p == 0) 274 p = &proc0; 275 } else { 276 long xaddr = (long)addr; 277 if (xaddr & 0x40000000) 278 pte = &p->p_vmspace->vm_map.pmap->pm_p1br[xaddr & 279 ~0x40000000]; 280 else 281 pte = &p->p_vmspace->vm_map.pmap->pm_p0br[xaddr]; 282 } 283 284 if (map) { 285 io = &map[reg]; 286 while (--npf > 0) { 287 pfnum = pte->pg_pfn; 288 if (pfnum == 0) 289 panic("mapin zero entry"); 290 pte++; 291 *(volatile int *)io++ = pfnum | flag; 292 } 293 *(volatile int *)io = 0; 294 } 295 } 296