1 /* $NetBSD: disksubr.c,v 1.1.1.1 1995/03/26 07:12:18 leo Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Leo Weppelman. 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Leo Weppelman. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/buf.h> 35 #include <sys/disklabel.h> 36 #include <machine/tospart.h> 37 38 #define b_cylin b_resid 39 #define baddr(bp) (void *)((bp)->b_un.b_addr) 40 41 /* 42 * Stash TOS partition info in here before handling. 43 */ 44 typedef struct { 45 u_long nblocks; 46 u_long blkoff; 47 u_long type; 48 } TMP_PART; 49 50 #define ROOT_FLAG 0x8000 /* Added in TMP_PART.type when NBR */ 51 52 static char *rd_tosparts __P((TMP_PART *,dev_t,void (*)(),struct disklabel *)); 53 static int get_type __P((u_char *)); 54 55 /* XXX unknown function but needed for /sys/scsi to link */ 56 int 57 dk_establish() 58 { 59 return(-1); 60 } 61 62 /* 63 * Attempt to read a disk label from a device 64 * using the indicated stategy routine. 65 * The label must be partly set up before this: 66 * secpercyl and anything required in the strategy routine 67 * (e.g., sector size) must be filled in before calling us. 68 * Returns null on success and an error string on failure. 69 */ 70 char * 71 readdisklabel(dev, strat, lp, clp) 72 dev_t dev; 73 void (*strat)(); 74 struct disklabel *lp; 75 struct cpu_disklabel *clp; 76 { 77 TMP_PART sizes[TOS_MAXPART]; 78 char *msg; 79 int i; 80 int usr_part = RAW_PART; 81 82 bzero(sizes, sizeof(sizes)); 83 if((msg = rd_tosparts(sizes, dev, strat, lp)) != NULL) 84 return(msg); 85 86 /* 87 * give some guarnteed validity to 88 * the disklabel 89 */ 90 if(lp->d_secperunit == 0) 91 lp->d_secperunit = 0x1fffffff; 92 if(lp->d_secpercyl == 0) 93 return("Zero secpercyl"); 94 lp->d_npartitions = RAW_PART + 1; 95 96 for(i = 0; i < MAXPARTITIONS; i++) { 97 if(i == RAW_PART) 98 continue; 99 lp->d_partitions[i].p_size = 0; 100 lp->d_partitions[i].p_offset = 0; 101 } 102 103 /* 104 * Now map the partition table from TOS to the NetBSD table. 105 * 106 * This means: 107 * Part 0 : Root 108 * Part 1 : Swap 109 * Part 2 : Whole disk 110 * Part 3.. : User partitions 111 * 112 * When more than one root partition is found, the only the first one 113 * will be recognized as such. The others are mapped as user partitions. 114 */ 115 lp->d_partitions[RAW_PART].p_size = sizes[0].nblocks; 116 lp->d_partitions[RAW_PART].p_offset = sizes[0].blkoff; 117 118 for(i = 0; sizes[i].nblocks; i++) { 119 int have_root = 0; 120 int pno; 121 122 if(!have_root && (sizes[i].type & ROOT_FLAG)) { 123 lp->d_partitions[0].p_size = sizes[i].nblocks; 124 lp->d_partitions[0].p_offset = sizes[i].blkoff; 125 lp->d_partitions[0].p_fstype = FS_BSDFFS; 126 have_root++; 127 continue; 128 } 129 switch(sizes[i].type &= ~ROOT_FLAG) { 130 case FS_SWAP: 131 pno = 1; 132 break; 133 case FS_BSDFFS: 134 case FS_MSDOS: 135 pno = ++usr_part; 136 break; 137 default: 138 continue; 139 } 140 if(pno >= MAXPARTITIONS) 141 break; /* XXX */ 142 lp->d_partitions[pno].p_size = sizes[i].nblocks; 143 lp->d_partitions[pno].p_offset = sizes[i].blkoff; 144 lp->d_partitions[pno].p_fstype = sizes[i].type; 145 } 146 lp->d_npartitions = usr_part + 1; 147 lp->d_secperunit = sizes[0].nblocks; 148 149 /* 150 * calulate new checksum. 151 */ 152 lp->d_magic = lp->d_magic2 = DISKMAGIC; 153 lp->d_checksum = 0; 154 lp->d_checksum = dkcksum(lp); 155 156 return(NULL); 157 } 158 159 /* 160 * Check new disk label for sensibility 161 * before setting it. 162 */ 163 int 164 setdisklabel(olp, nlp, openmask, clp) 165 register struct disklabel *olp, *nlp; 166 u_long openmask; 167 struct cpu_disklabel *clp; 168 { 169 return (EINVAL); 170 } 171 172 /* 173 * Write disk label back to device after modification. 174 */ 175 int 176 writedisklabel(dev, strat, lp, clp) 177 dev_t dev; 178 void (*strat)(); 179 register struct disklabel *lp; 180 struct cpu_disklabel *clp; 181 { 182 return(EINVAL); 183 } 184 185 186 int 187 bounds_check_with_label(bp, lp, wlabel) 188 struct buf *bp; 189 struct disklabel *lp; 190 int wlabel; 191 { 192 struct partition *pp; 193 long maxsz, sz; 194 195 pp = &lp->d_partitions[DISKPART(bp->b_dev)]; 196 if(bp->b_flags & B_RAW) { 197 maxsz = pp->p_size * (lp->d_secsize / DEV_BSIZE); 198 sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; 199 } 200 else { 201 maxsz = pp->p_size; 202 sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; 203 } 204 205 if(bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { 206 if(bp->b_blkno == maxsz) { 207 /* 208 * trying to get one block beyond return EOF. 209 */ 210 bp->b_resid = bp->b_bcount; 211 return(0); 212 } 213 sz = maxsz - bp->b_blkno; 214 if(sz <= 0 || bp->b_blkno < 0) { 215 bp->b_error = EINVAL; 216 bp->b_flags |= B_ERROR; 217 return(-1); 218 } 219 /* 220 * adjust count down 221 */ 222 if(bp->b_flags & B_RAW) 223 bp->b_bcount = sz << DEV_BSHIFT; 224 else bp->b_bcount = sz * lp->d_secsize; 225 } 226 227 /* 228 * calc cylinder for disksort to order transfers with 229 */ 230 bp->b_cylin = (bp->b_blkno + pp->p_offset) / lp->d_secpercyl; 231 return(1); 232 } 233 234 /* 235 * Read a GEM-partition info and translate it to our temporary partitions array. 236 * Returns 0 if an error occured, 1 if all went ok. 237 */ 238 #define BP_SETUP(bp, block) { \ 239 bp->b_blkno = block; \ 240 bp->b_cylin = block / lp->d_secpercyl; \ 241 bp->b_bcount = TOS_BSIZE; \ 242 bp->b_flags = B_BUSY | B_READ; \ 243 } 244 245 static char * 246 rd_tosparts(sizes, dev, strat, lp) 247 TMP_PART *sizes; 248 dev_t dev; 249 void (*strat)(); 250 struct disklabel *lp; 251 { 252 GEM_ROOT *g_root; 253 GEM_PART g_local[NGEM_PARTS]; 254 struct buf *bp; 255 int pno = 1; 256 char *msg = NULL; 257 int i; 258 259 /* 260 * Get a buffer first, so we can read the disk. 261 */ 262 bp = (void*)geteblk(TOS_BSIZE); 263 bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART); 264 265 /* 266 * Read root sector 267 */ 268 BP_SETUP(bp, TOS_BBLOCK); 269 strat(bp); 270 if(biowait(bp)) { 271 msg = "I/O error"; 272 goto done; 273 } 274 275 /* 276 * Make local copy of partition info, we may need to re-use 277 * the buffer in case of 'XGM' partitions. 278 */ 279 g_root = (GEM_ROOT*)baddr(bp); 280 bcopy(g_root->parts, g_local, NGEM_PARTS*sizeof(GEM_PART)); 281 282 /* 283 * Partition 0 contains whole disk! 284 */ 285 sizes[0].nblocks = g_root->hd_siz; 286 sizes[0].blkoff = 0; 287 sizes[0].type = FS_UNUSED; 288 289 for(i = 0; i < NGEM_PARTS; i++) { 290 if(!(g_local[i].p_flg & 1)) 291 continue; 292 if(!strncmp(g_local[i].p_id, "XGM", 3)) { 293 int j; 294 daddr_t new_root = g_local[i].p_st; 295 296 /* 297 * Loop through extended partition list 298 */ 299 for(;;) { 300 BP_SETUP(bp, new_root); 301 strat(bp); 302 if(biowait(bp)) { 303 msg = "I/O error"; 304 goto done; 305 } 306 for(j = 0; j < NGEM_PARTS; j++) { 307 if(!(g_root->parts[j].p_flg & 1)) 308 continue; 309 if(!strncmp(g_root->parts[j].p_id, "XGM", 3)) { 310 new_root = g_local[i].p_st + g_root->parts[j].p_st; 311 break; 312 } 313 else { 314 sizes[pno].nblocks=g_root->parts[j].p_size; 315 sizes[pno].blkoff =g_root->parts[j].p_st+new_root; 316 sizes[pno].type =get_type(g_root->parts[j].p_id); 317 pno++; 318 if(pno >= TOS_MAXPART) 319 break; 320 } 321 } 322 if(j == NGEM_PARTS) 323 break; 324 } 325 } 326 else { 327 sizes[pno].nblocks = g_local[i].p_size; 328 sizes[pno].blkoff = g_local[i].p_st; 329 sizes[pno].type = get_type(g_local[i].p_id); 330 pno++; 331 } 332 } 333 /* 334 * Check sensibility of partition info 335 */ 336 for(i = 2; i < pno; i++) { 337 if(sizes[i].blkoff < (sizes[i-1].blkoff + sizes[i-1].nblocks)) { 338 msg = "Partion table bad (overlap)"; 339 goto done; 340 } 341 if((sizes[i].blkoff + sizes[i].nblocks) > sizes[0].nblocks) { 342 msg = "Partion table bad (extends beyond disk)"; 343 goto done; 344 } 345 } 346 done: 347 bp->b_flags = B_INVAL | B_AGE | B_READ; 348 brelse(bp); 349 return(msg); 350 } 351 352 /* 353 * Translate a TOS partition type to a NetBSD partition type. 354 */ 355 #define ID_CMP(a,b) ((a[0] == b[0]) && (a[1] == b[1]) && (a[2] == b[2])) 356 357 static int 358 get_type(p_id) 359 u_char *p_id; 360 { 361 if(ID_CMP(p_id, "GEM") || ID_CMP(p_id, "BGM")) 362 return(FS_MSDOS); /* XXX - should be compatible */ 363 if(ID_CMP(p_id, "NBU")) 364 return(FS_BSDFFS); 365 if(ID_CMP(p_id, "NBR")) 366 return(FS_BSDFFS|ROOT_FLAG); 367 if(ID_CMP(p_id, "NBS")) 368 return(FS_SWAP); 369 return(FS_OTHER); 370 } 371