1 /* $NetBSD: disksubr.c,v 1.36 2019/04/03 22:10:50 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Dale Rahn. 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. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.36 2019/04/03 22:10:50 christos Exp $"); 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/buf.h> 36 #include <sys/device.h> 37 #define FSTYPENAMES 38 #include <sys/disklabel.h> 39 #include <sys/disk.h> 40 41 #include <dev/scsipi/scsi_all.h> 42 #include <dev/scsipi/scsipi_all.h> 43 #include <dev/scsipi/scsiconf.h> 44 45 #include <machine/autoconf.h> 46 47 #ifdef DEBUG 48 int disksubr_debug = 0; 49 #endif 50 51 static void bsdtocpulabel(struct disklabel *lp, struct cpu_disklabel *clp); 52 static void cputobsdlabel(struct disklabel *lp, struct cpu_disklabel *clp); 53 54 #ifdef DEBUG 55 static void printlp(struct disklabel *lp, const char *str); 56 static void printclp(struct cpu_disklabel *clp, const char *str); 57 #endif 58 59 60 /* 61 * Attempt to read a disk label from a device 62 * using the indicated strategy routine. 63 * The label must be partly set up before this: 64 * secpercyl and anything required in the strategy routine 65 * (e.g., sector size) must be filled in before calling us. 66 * Returns null on success and an error string on failure. 67 */ 68 const char * 69 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 70 struct cpu_disklabel *clp) 71 { 72 struct buf *bp; 73 const char *msg = NULL; 74 75 /* obtain buffer to probe drive with */ 76 bp = geteblk((int)lp->d_secsize); 77 78 /* request no partition relocation by driver on I/O operations */ 79 bp->b_dev = dev; 80 bp->b_blkno = 0; /* contained in block 0 */ 81 bp->b_bcount = lp->d_secsize; 82 bp->b_flags |= B_READ; 83 bp->b_cylinder = 0; /* contained in block 0 */ 84 (*strat)(bp); 85 86 if (biowait(bp)) { 87 msg = "cpu_disklabel read error\n"; 88 } else { 89 memcpy(clp, bp->b_data, sizeof (struct cpu_disklabel)); 90 } 91 92 brelse(bp, 0); 93 94 if (msg || clp->magic1 != DISKMAGIC || clp->magic2 != DISKMAGIC) { 95 return msg; 96 } 97 98 cputobsdlabel(lp, clp); 99 #ifdef DEBUG 100 if(disksubr_debug > 0) { 101 printlp(lp, "readdisklabel: bsd label"); 102 printclp(clp, "readdisklabel: cpu label"); 103 } 104 #endif 105 return msg; 106 } 107 108 /* 109 * Write disk label back to device after modification. 110 */ 111 int 112 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 113 struct cpu_disklabel *clp) 114 { 115 struct buf *bp; 116 int error; 117 118 #ifdef DEBUG 119 if(disksubr_debug > 0) { 120 printlp(lp, "writedisklabel: bsd label"); 121 } 122 #endif 123 124 /* 125 * obtain buffer to read initial cpu_disklabel, for bootloader size :-) 126 */ 127 bp = geteblk((int)lp->d_secsize); 128 129 /* request no partition relocation by driver on I/O operations */ 130 bp->b_dev = dev; 131 bp->b_blkno = 0; /* contained in block 0 */ 132 bp->b_bcount = lp->d_secsize; 133 bp->b_flags |= B_READ; 134 bp->b_cylinder = 0; /* contained in block 0 */ 135 (*strat)(bp); 136 137 if ( (error = biowait(bp)) != 0 ) { 138 /* nothing */ 139 } else { 140 memcpy(clp, bp->b_data, sizeof(struct cpu_disklabel)); 141 } 142 143 brelse(bp, 0); 144 145 if (error) { 146 return error; 147 } 148 149 bsdtocpulabel(lp, clp); 150 151 #ifdef DEBUG 152 if (disksubr_debug > 0) { 153 printclp(clp, "writedisklabel: cpu label"); 154 } 155 #endif 156 157 if (lp->d_magic == DISKMAGIC && lp->d_magic2 == DISKMAGIC && 158 dkcksum(lp) == 0) { 159 /* obtain buffer to scrozz drive with */ 160 bp = geteblk((int)lp->d_secsize); 161 162 memcpy(bp->b_data, clp, sizeof(struct cpu_disklabel)); 163 164 /* 165 * request no partition relocation by driver on I/O operations 166 */ 167 bp->b_dev = dev; 168 bp->b_blkno = 0; /* contained in block 0 */ 169 bp->b_bcount = lp->d_secsize; 170 bp->b_flags |= B_WRITE; 171 bp->b_cylinder = 0; /* contained in block 0 */ 172 (*strat)(bp); 173 174 error = biowait(bp); 175 176 brelse(bp, 0); 177 } 178 return error; 179 } 180 181 static void 182 bsdtocpulabel(struct disklabel *lp, struct cpu_disklabel *clp) 183 { 184 int i; 185 186 clp->magic1 = lp->d_magic; 187 clp->type = lp->d_type; 188 clp->subtype = lp->d_subtype; 189 strncpy(clp->vid_vd, lp->d_typename, 16); 190 strncpy(clp->packname, lp->d_packname, 16); 191 clp->cfg_psm = lp->d_secsize; 192 clp->cfg_spt = lp->d_nsectors; 193 clp->cfg_trk = lp->d_ncylinders; /* trk is really num of cyl! */ 194 clp->cfg_hds = lp->d_ntracks; 195 196 clp->secpercyl = lp->d_secpercyl; 197 clp->secperunit = lp->d_secperunit; 198 clp->sparespertrack = lp->d_sparespertrack; 199 clp->sparespercyl = lp->d_sparespercyl; 200 clp->acylinders = lp->d_acylinders; 201 clp->rpm = lp->d_rpm; 202 203 clp->cfg_ilv = lp->d_interleave; 204 clp->cfg_sof = lp->d_trackskew; 205 clp->cylskew = lp->d_cylskew; 206 clp->headswitch = lp->d_headswitch; 207 208 /* this silly table is for winchester drives */ 209 if (lp->d_trkseek < 6) { 210 clp->cfg_ssr = 0; 211 } else if (lp->d_trkseek < 10) { 212 clp->cfg_ssr = 1; 213 } else if (lp->d_trkseek < 15) { 214 clp->cfg_ssr = 2; 215 } else if (lp->d_trkseek < 20) { 216 clp->cfg_ssr = 3; 217 } else { 218 clp->cfg_ssr = 4; 219 } 220 221 clp->flags = lp->d_flags; 222 for (i = 0; i < NDDATA; i++) 223 clp->drivedata[i] = lp->d_drivedata[i]; 224 for (i = 0; i < NSPARE; i++) 225 clp->spare[i] = lp->d_spare[i]; 226 227 clp->magic2 = lp->d_magic2; 228 clp->checksum = lp->d_checksum; 229 clp->partitions = lp->d_npartitions; 230 clp->bbsize = lp->d_bbsize; 231 clp->sbsize = lp->d_sbsize; 232 clp->checksum = lp->d_checksum; 233 /* note: assume at least 4 partitions */ 234 memcpy(clp->vid_4, &lp->d_partitions[0], sizeof(struct partition) * 4); 235 memset(clp->cfg_4, 0, sizeof(struct partition) * 12); 236 memcpy(clp->cfg_4, &lp->d_partitions[4], sizeof(struct partition) 237 * ((MAXPARTITIONS < 16) ? (MAXPARTITIONS - 4) : 12)); 238 239 /* 240 * here are the parts of the cpu_disklabel the kernel must init. 241 * see disklabel.h for more details 242 * [note: this used to be handled by 'wrtvid'] 243 */ 244 memcpy(clp->vid_id, VID_ID, sizeof(clp->vid_id)); 245 clp->vid_oss = VID_OSS; 246 clp->vid_osl = VID_OSL; 247 clp->vid_osa_u = VID_OSAU; 248 clp->vid_osa_l = VID_OSAL; 249 clp->vid_cas = VID_CAS; 250 clp->vid_cal = VID_CAL; 251 memcpy(clp->vid_mot, VID_MOT, sizeof(clp->vid_mot)); 252 clp->cfg_rec = CFG_REC; 253 clp->cfg_psm = CFG_PSM; 254 } 255 256 static void 257 cputobsdlabel(struct disklabel *lp, struct cpu_disklabel *clp) 258 { 259 int i; 260 261 lp->d_magic = clp->magic1; 262 lp->d_type = clp->type; 263 lp->d_subtype = clp->subtype; 264 strncpy(lp->d_typename, clp->vid_vd, 16); 265 strncpy(lp->d_packname, clp->packname, 16); 266 lp->d_secsize = clp->cfg_psm; 267 lp->d_nsectors = clp->cfg_spt; 268 lp->d_ncylinders = clp->cfg_trk; /* trk is really num of cyl! */ 269 lp->d_ntracks = clp->cfg_hds; 270 271 lp->d_secpercyl = clp->secpercyl; 272 lp->d_secperunit = clp->secperunit; 273 lp->d_secpercyl = clp->secpercyl; 274 lp->d_secperunit = clp->secperunit; 275 lp->d_sparespertrack = clp->sparespertrack; 276 lp->d_sparespercyl = clp->sparespercyl; 277 lp->d_acylinders = clp->acylinders; 278 lp->d_rpm = clp->rpm; 279 lp->d_interleave = clp->cfg_ilv; 280 lp->d_trackskew = clp->cfg_sof; 281 lp->d_cylskew = clp->cylskew; 282 lp->d_headswitch = clp->headswitch; 283 284 /* this silly table is for winchester drives */ 285 switch (clp->cfg_ssr) { 286 case 0: 287 lp->d_trkseek = 0; 288 break; 289 case 1: 290 lp->d_trkseek = 6; 291 break; 292 case 2: 293 lp->d_trkseek = 10; 294 break; 295 case 3: 296 lp->d_trkseek = 15; 297 break; 298 case 4: 299 lp->d_trkseek = 20; 300 break; 301 default: 302 lp->d_trkseek = 0; 303 } 304 lp->d_flags = clp->flags; 305 for (i = 0; i < NDDATA; i++) 306 lp->d_drivedata[i] = clp->drivedata[i]; 307 for (i = 0; i < NSPARE; i++) 308 lp->d_spare[i] = clp->spare[i]; 309 310 lp->d_magic2 = clp->magic2; 311 lp->d_checksum = clp->checksum; 312 lp->d_npartitions = clp->partitions; 313 lp->d_bbsize = clp->bbsize; 314 lp->d_sbsize = clp->sbsize; 315 /* note: assume at least 4 partitions */ 316 memcpy(&lp->d_partitions[0], clp->vid_4, sizeof(struct partition) * 4); 317 memcpy(&lp->d_partitions[4], clp->cfg_4, sizeof(struct partition) 318 * ((MAXPARTITIONS < 16) ? (MAXPARTITIONS - 4) : 12)); 319 lp->d_checksum = 0; 320 lp->d_checksum = dkcksum(lp); 321 #if DEBUG 322 if (disksubr_debug > 0) { 323 printlp(lp, "translated label read from disk\n"); 324 } 325 #endif 326 } 327 328 #ifdef DEBUG 329 static void 330 printlp(struct disklabel *lp, const char *str) 331 { 332 int i; 333 334 printf("%s\n", str); 335 printf("magic1 %x\n", lp->d_magic); 336 printf("magic2 %x\n", lp->d_magic2); 337 printf("typename %s\n", lp->d_typename); 338 printf("secsize %x nsect %x ntrack %x ncylinders %x\n", 339 lp->d_secsize, lp->d_nsectors, lp->d_ntracks, lp->d_ncylinders); 340 printf("Num partitions %x\n", lp->d_npartitions); 341 for (i = 0; i < lp->d_npartitions; i++) { 342 struct partition *part = &lp->d_partitions[i]; 343 const char *fstyp = fstypenames[part->p_fstype]; 344 345 printf("%c: size %10x offset %10x type %7s frag %5x cpg %3x\n", 346 'a' + i, part->p_size, part->p_offset, fstyp, 347 part->p_frag, part->p_cpg); 348 } 349 } 350 351 static void 352 printclp(struct cpu_disklabel *clp, const char *str) 353 { 354 int maxp, i; 355 356 printf("%s\n", str); 357 printf("magic1 %lx\n", clp->magic1); 358 printf("magic2 %lx\n", clp->magic2); 359 printf("typename %s\n", clp->vid_vd); 360 printf("secsize %x nsect %x ntrack %x ncylinders %x\n", 361 clp->cfg_psm, clp->cfg_spt, clp->cfg_hds, clp->cfg_trk); 362 printf("Num partitions %x\n", clp->partitions); 363 maxp = clp->partitions < 16 ? clp->partitions : 16; 364 for (i = 0; i < maxp; i++) { 365 struct partition *part; 366 const char *fstyp; 367 368 if (i < 4) { 369 part = (void *)&clp->vid_4[0]; 370 part = &part[i]; 371 } else { 372 part = (void *)&clp->cfg_4[0]; 373 part = &part[i-4]; 374 } 375 376 fstyp = fstypenames[part->p_fstype]; 377 378 printf("%c: size %10x offset %10x type %7s frag %5x cpg %3x\n", 379 'a' + i, part->p_size, part->p_offset, fstyp, 380 part->p_frag, part->p_cpg); 381 } 382 } 383 #endif 384