1 /* $NetBSD: disksubr.c,v 1.55 2026/05/30 10:10:11 thorpej 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.55 2026/05/30 10:10:11 thorpej 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/disklabel.h> 44 #include <sys/disk.h> 45 #include <sys/syslog.h> 46 #include <sys/proc.h> 47 48 #include <uvm/uvm_extern.h> 49 50 #include <machine/macros.h> 51 52 #include <dev/mscp/mscp.h> /* For disk encoding scheme */ 53 54 #ifdef COMPAT_ULTRIX 55 #include <dev/dec/dec_boot.h> 56 #include <ufs/ufs/dinode.h> /* XXX for fs.h */ 57 #include <ufs/ffs/fs.h> /* XXX for BBSIZE & SBSIZE */ 58 59 static const char *compat_label(dev_t dev, void (*strat)(struct buf *bp), 60 struct disklabel *lp, struct cpu_disklabel *osdep); 61 #endif /* COMPAT_ULTRIX */ 62 63 /* 64 * Attempt to read a disk label from a device 65 * using the indicated strategy routine. 66 * The label must be partly set up before this: 67 * secpercyl and anything required in the strategy routine 68 * (e.g., sector size) must be filled in before calling us. 69 * Returns null on success and an error string on failure. 70 */ 71 const char * 72 readdisklabel(dev_t dev, void (*strat)(struct buf *), 73 struct disklabel *lp, struct cpu_disklabel *osdep) 74 { 75 struct buf *bp; 76 struct disklabel *dlp; 77 const char *msg = NULL; 78 79 if (lp->d_npartitions == 0) { /* Assume no label */ 80 lp->d_secperunit = 0x1fffffff; 81 lp->d_npartitions = 3; 82 lp->d_partitions[2].p_size = 0x1fffffff; 83 lp->d_partitions[2].p_offset = 0; 84 } 85 86 bp = geteblk((int)lp->d_secsize); 87 bp->b_dev = dev; 88 bp->b_blkno = LABELSECTOR; 89 bp->b_bcount = lp->d_secsize; 90 bp->b_flags |= B_READ; 91 bp->b_cylinder = LABELSECTOR / lp->d_secpercyl; 92 (*strat)(bp); 93 if (biowait(bp)) { 94 msg = "I/O error"; 95 } else { 96 dlp = (struct disklabel *)((char *)bp->b_data + LABELOFFSET); 97 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { 98 msg = "no disk label"; 99 } else if (dlp->d_npartitions > MAXPARTITIONS || 100 dkcksum(dlp) != 0) 101 msg = "disk label corrupted"; 102 else { 103 *lp = *dlp; 104 } 105 } 106 brelse(bp, 0); 107 108 #ifdef COMPAT_ULTRIX 109 /* 110 * If no NetBSD label was found, check for an Ultrix label and 111 * construct tne incore label from the Ultrix partition information. 112 */ 113 if (msg != NULL) { 114 msg = compat_label(dev, strat, lp, osdep); 115 if (msg == NULL) { 116 printf("WARNING: using Ultrix partition information\n"); 117 /* set geometry? */ 118 } 119 } 120 #endif 121 return (msg); 122 } 123 124 #ifdef COMPAT_ULTRIX 125 /* 126 * Given a buffer bp, try and interpret it as an Ultrix disk label, 127 * putting the partition info into a native NetBSD label 128 */ 129 const char * 130 compat_label(dev_t dev, void (*strat)(struct buf *bp), struct disklabel *lp, 131 struct cpu_disklabel *osdep) 132 { 133 dec_disklabel *dlp; 134 struct buf *bp = NULL; 135 const char *msg = NULL; 136 uint8_t *dp; 137 138 bp = geteblk((int)lp->d_secsize); 139 dp = bp->b_data; 140 bp->b_dev = dev; 141 bp->b_blkno = DEC_LABEL_SECTOR; 142 bp->b_bcount = lp->d_secsize; 143 bp->b_flags |= B_READ; 144 bp->b_cylinder = DEC_LABEL_SECTOR / lp->d_secpercyl; 145 (*strat)(bp); 146 147 if (biowait(bp)) { 148 msg = "I/O error"; 149 goto done; 150 } 151 152 for (dlp = (dec_disklabel *)dp; 153 dlp <= (dec_disklabel *)(dp+DEV_BSIZE-sizeof(*dlp)); 154 dlp = (dec_disklabel *)((char *)dlp + sizeof(long))) { 155 156 int part; 157 158 if (dlp->magic != DEC_LABEL_MAGIC) { 159 if (dlp->magic != 0) 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 * Write disk label back to device after modification. 202 * Always allow writing of disk label; even if the disk is unlabeled. 203 */ 204 int 205 writedisklabel(dev_t dev, void (*strat)(struct buf *), 206 struct disklabel *lp, struct cpu_disklabel *osdep) 207 { 208 struct buf *bp; 209 struct disklabel *dlp; 210 int error = 0; 211 212 bp = geteblk((int)lp->d_secsize); 213 bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART); 214 bp->b_blkno = LABELSECTOR; 215 bp->b_bcount = lp->d_secsize; 216 bp->b_flags |= B_READ; 217 (*strat)(bp); 218 if ((error = biowait(bp))) 219 goto done; 220 dlp = (struct disklabel *)((char *)bp->b_data + LABELOFFSET); 221 memcpy(dlp, lp, sizeof(struct disklabel)); 222 bp->b_oflags &= ~(BO_DONE); 223 bp->b_flags &= ~(B_READ); 224 bp->b_flags |= B_WRITE; 225 (*strat)(bp); 226 error = biowait(bp); 227 228 done: 229 brelse(bp, 0); 230 return (error); 231 } 232 233 /* 234 * Print out the name of the device; ex. TK50, RA80. DEC uses a common 235 * disk type encoding scheme for most of its disks. 236 */ 237 void 238 disk_printtype(int unit, int type) 239 { 240 printf(" drive %d: %c%c", unit, (int)MSCP_MID_CHAR(2, type), 241 (int)MSCP_MID_CHAR(1, type)); 242 if (MSCP_MID_ECH(0, type)) 243 printf("%c", (int)MSCP_MID_CHAR(0, type)); 244 printf("%d\n", MSCP_MID_NUM(type)); 245 } 246 247 /* 248 * Be sure that the pages we want to do DMA to is actually there 249 * by faking page-faults if necessary. If given a map-register address, 250 * also map it in. 251 */ 252 void 253 disk_reallymapin(struct buf *bp, struct pte *map, int reg, int flag) 254 { 255 struct proc *p; 256 volatile pt_entry_t *io; 257 pt_entry_t *pte; 258 int pfnum, npf, o; 259 void *addr; 260 261 o = (int)bp->b_data & VAX_PGOFSET; 262 npf = vax_btoc(bp->b_bcount + o) + 1; 263 addr = bp->b_data; 264 p = bp->b_proc; 265 266 /* 267 * Get a pointer to the pte pointing out the first virtual address. 268 * Use different ways in kernel and user space. 269 */ 270 if ((bp->b_flags & B_PHYS) == 0) { 271 pte = kvtopte(addr); 272 if (p == 0) 273 p = &proc0; 274 } else { 275 long xaddr = (long)addr; 276 if (xaddr & 0x40000000) 277 pte = &p->p_vmspace->vm_map.pmap->pm_p1br[xaddr & 278 ~0x40000000]; 279 else 280 pte = &p->p_vmspace->vm_map.pmap->pm_p0br[xaddr]; 281 } 282 283 if (map) { 284 io = &map[reg]; 285 while (--npf > 0) { 286 pfnum = pte->pg_pfn; 287 if (pfnum == 0) 288 panic("mapin zero entry"); 289 pte++; 290 *(volatile int *)io++ = pfnum | flag; 291 } 292 *(volatile int *)io = 0; 293 } 294 } 295