char canonical_unit(struct disklabel *lp, char unit) { struct partition *pp; u_int64_t small; int i; if (unit == '*') { small = DL_GETDSIZE(lp); pp = &lp->d_partitions[0]; for (i = 0; i < lp->d_npartitions; i++, pp++) if (DL_GETPSIZE(pp) > 0 && DL_GETPSIZE(pp) < small) small = DL_GETPSIZE(pp); if (small < DL_BLKTOSEC(lp, MEG(1))) unit = 'K'; else if (small < DL_BLKTOSEC(lp, MEG(1024))) unit = 'M'; else if (small < DL_BLKTOSEC(lp, GIG(1024))) unit = 'G'; else unit = 'T'; } unit = toupper((unsigned char)unit); return (unit); }
/* * Write disk label back to device after modification. */ int writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp) { daddr_t partoff = -1; int error = EIO; int offset; struct disklabel *dlp; struct buf *bp = NULL; /* get a buffer and initialize it */ bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; /* Read it in, slap the new label in, and write it back out */ error = readvdmlabel(bp, strat, lp, &partoff, 1); if (error == 0 || error == ENOENT) { error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, partoff + LABELSECTOR)); offset = LABELOFFSET; } else if (readdoslabel(bp, strat, lp, &partoff, 1) == 0) { error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, partoff + DOS_LABELSECTOR)); offset = DL_BLKOFFSET(lp, partoff + DOS_LABELSECTOR); } else { error = EIO; goto done; } if (error) goto done; dlp = (struct disklabel *)(bp->b_data + offset); *dlp = *lp; CLR(bp->b_flags, B_READ | B_WRITE | B_DONE); SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW); (*strat)(bp); error = biowait(bp); done: if (bp) { bp->b_flags |= B_INVAL; brelse(bp); } disk_change = 1; return (error); }
void __wdstart(struct wd_softc *wd, struct buf *bp) { struct disklabel *lp; u_int64_t nsecs; lp = wd->sc_dk.dk_label; wd->sc_wdc_bio.blkno = DL_BLKTOSEC(lp, bp->b_blkno + DL_SECTOBLK(lp, DL_GETPOFFSET(&lp->d_partitions[DISKPART(bp->b_dev)]))); wd->sc_wdc_bio.blkdone =0; wd->sc_bp = bp; /* * If we're retrying, retry in single-sector mode. This will give us * the sector number of the problem, and will eventually allow the * transfer to succeed. */ if (wd->retries >= WDIORETRIES_SINGLE) wd->sc_wdc_bio.flags = ATA_SINGLE; else wd->sc_wdc_bio.flags = 0; nsecs = howmany(bp->b_bcount, lp->d_secsize); if ((wd->sc_flags & WDF_LBA48) && /* use LBA48 only if really need */ ((wd->sc_wdc_bio.blkno + nsecs - 1 >= LBA48_THRESHOLD) || (nsecs > 0xff))) wd->sc_wdc_bio.flags |= ATA_LBA48; if (wd->sc_flags & WDF_LBA) wd->sc_wdc_bio.flags |= ATA_LBA; if (bp->b_flags & B_READ) wd->sc_wdc_bio.flags |= ATA_READ; wd->sc_wdc_bio.bcount = bp->b_bcount; wd->sc_wdc_bio.databuf = bp->b_data; wd->sc_wdc_bio.wd = wd; /* Instrumentation. */ disk_busy(&wd->sc_dk); switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) { case WDC_TRY_AGAIN: timeout_add_sec(&wd->sc_restart_timeout, 1); break; case WDC_QUEUED: break; case WDC_COMPLETE: /* * This code is never executed because we never set * the ATA_POLL flag above */ #if 0 if (wd->sc_wdc_bio.flags & ATA_POLL) wddone(wd); #endif break; default: panic("__wdstart: bad return code from wdc_ata_bio()"); } }
/* * Attempt to read a disk label from a device * using the indicated strategy routine. * The label must be partly set up before this: * secpercyl, secsize and anything required for a block i/o read * operation in the driver's strategy/start routines * must be filled in before calling us. */ int readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, int spoofonly) { struct sun_disklabel *slp; struct buf *bp = NULL; int error; if ((error = initdisklabel(lp))) goto done; lp->d_flags |= D_VENDOR; /* get a buffer and initialize it */ bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; if (spoofonly) goto done; error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, LABELSECTOR)); if (error) goto done; slp = (struct sun_disklabel *)bp->b_data; if (slp->sl_magic == SUN_DKMAGIC) { error = disklabel_om_to_bsd(slp, lp); goto done; } error = checkdisklabel(bp->b_data + LABELOFFSET, lp, 0, DL_GETDSIZE(lp)); if (error == 0) goto done; #if defined(CD9660) error = iso_disklabelspoof(dev, strat, lp); if (error == 0) goto done; #endif #if defined(UDF) error = udf_disklabelspoof(dev, strat, lp); if (error == 0) goto done; #endif done: if (bp) { bp->b_flags |= B_INVAL; brelse(bp); } disk_change = 1; return (error); }
/* * Write disk label back to device after modification. */ int writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp) { daddr_t partoff = -1; int error = EIO; int offset; struct disklabel *dlp; struct buf *bp = NULL; /* get a buffer and initialize it */ bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; if (readgptlabel(bp, strat, lp, &partoff, 1) != 0 && readdoslabel(bp, strat, lp, &partoff, 1) != 0) goto done; /* Read it in, slap the new label in, and write it back out */ bp->b_blkno = DL_BLKTOSEC(lp, partoff + DOS_LABELSECTOR) * DL_BLKSPERSEC(lp); offset = DL_BLKOFFSET(lp, partoff + DOS_LABELSECTOR); bp->b_bcount = lp->d_secsize; CLR(bp->b_flags, B_READ | B_WRITE | B_DONE); SET(bp->b_flags, B_BUSY | B_READ | B_RAW); (*strat)(bp); if ((error = biowait(bp)) != 0) goto done; dlp = (struct disklabel *)(bp->b_data + offset); *dlp = *lp; CLR(bp->b_flags, B_READ | B_WRITE | B_DONE); SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW); (*strat)(bp); error = biowait(bp); done: if (bp) { bp->b_flags |= B_INVAL; brelse(bp); } disk_change = 1; return (error); }
/* * Attempt to read a disk label from a device * using the indicated strategy routine. * The label must be partly set up before this: * secpercyl, secsize and anything required for a block i/o read * operation in the driver's strategy/start routines * must be filled in before calling us. */ int readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, int spoofonly) { struct sun_disklabel *slp; struct buf *bp = NULL; int error; if ((error = initdisklabel(lp))) goto done; lp->d_flags |= D_VENDOR; /* * On sparc64 we check for a CD label first, because our * CD install media contains both sparc & sparc64 labels. * We want the sparc64 machine to find the "CD label", not * the SunOS label, for loading its kernel. */ #if NCD > 0 if (strat == cdstrategy) { #if defined(CD9660) if (iso_disklabelspoof(dev, strat, lp) == 0) goto done; #endif #if defined(UDF) if (udf_disklabelspoof(dev, strat, lp) == 0) goto done; #endif } #endif /* NCD > 0 */ /* get buffer and initialize it */ bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; if (spoofonly) goto doslabel; error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, LABELSECTOR)); if (error) goto done; slp = (struct sun_disklabel *)bp->b_data; if (slp->sl_magic == SUN_DKMAGIC) { error = disklabel_sun_to_bsd(slp, lp); goto done; } error = checkdisklabel(bp->b_data + LABELOFFSET, lp, 0, DL_GETDSIZE(lp)); if (error == 0) goto done; doslabel: error = readdoslabel(bp, strat, lp, NULL, spoofonly); if (error == 0) goto done; /* A CD9660/UDF label may be on a non-CD drive, so recheck */ #if defined(CD9660) error = iso_disklabelspoof(dev, strat, lp); if (error == 0) goto done; #endif #if defined(UDF) error = udf_disklabelspoof(dev, strat, lp); if (error == 0) goto done; #endif done: if (bp) { bp->b_flags |= B_INVAL; brelse(bp); } disk_change = 1; return (error); }
/* * sdstart looks to see if there is a buf waiting for the device * and that the device is not already busy. If both are true, * It dequeues the buf and creates a scsi command to perform the * transfer in the buf. The transfer request will call scsi_done * on completion, which will in turn call this routine again * so that the next queued transfer is performed. * The bufs are queued by the strategy routine (sdstrategy) * * This routine is also called after other non-queued requests * have been made of the scsi driver, to ensure that the queue * continues to be drained. */ void sdstart(struct scsi_xfer *xs) { struct scsi_link *link = xs->sc_link; struct sd_softc *sc = link->device_softc; struct buf *bp; u_int64_t secno; int nsecs; int read; struct partition *p; if (sc->flags & SDF_DYING) { scsi_xs_put(xs); return; } if ((link->flags & SDEV_MEDIA_LOADED) == 0) { bufq_drain(&sc->sc_bufq); scsi_xs_put(xs); return; } bp = bufq_dequeue(&sc->sc_bufq); if (bp == NULL) { scsi_xs_put(xs); return; } secno = DL_BLKTOSEC(sc->sc_dk.dk_label, bp->b_blkno); p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; secno += DL_GETPOFFSET(p); nsecs = howmany(bp->b_bcount, sc->sc_dk.dk_label->d_secsize); read = bp->b_flags & B_READ; /* * Fill out the scsi command. If the transfer will * fit in a "small" cdb, use it. */ if (!(link->flags & SDEV_ATAPI) && !(link->quirks & SDEV_ONLYBIG) && ((secno & 0x1fffff) == secno) && ((nsecs & 0xff) == nsecs)) sd_cmd_rw6(xs, read, secno, nsecs); else if (((secno & 0xffffffff) == secno) && ((nsecs & 0xffff) == nsecs)) sd_cmd_rw10(xs, read, secno, nsecs); else if (((secno & 0xffffffff) == secno) && ((nsecs & 0xffffffff) == nsecs)) sd_cmd_rw12(xs, read, secno, nsecs); else sd_cmd_rw16(xs, read, secno, nsecs); xs->flags |= (read ? SCSI_DATA_IN : SCSI_DATA_OUT); xs->timeout = 60000; xs->data = bp->b_data; xs->datalen = bp->b_bcount; xs->done = sd_buf_done; xs->cookie = bp; xs->bp = bp; /* Instrumentation. */ disk_busy(&sc->sc_dk); /* Mark disk as dirty. */ if (!read) sc->flags |= SDF_DIRTY; scsi_xs_exec(xs); /* move onto the next io */ if (ISSET(sc->flags, SDF_WAITING)) CLR(sc->flags, SDF_WAITING); else if (bufq_peek(&sc->sc_bufq)) scsi_xsh_add(&sc->sc_xsh); }
/* * dump all of physical memory into the partition specified, starting * at offset 'dumplo' into the partition. */ int sddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) { struct sd_softc *sc; /* disk unit to do the I/O */ struct disklabel *lp; /* disk's disklabel */ int unit, part; u_int32_t sectorsize; /* size of a disk sector */ u_int64_t nsects; /* number of sectors in partition */ u_int64_t sectoff; /* sector offset of partition */ u_int64_t totwrt; /* total number of sectors left to write */ u_int32_t nwrt; /* current number of sectors to write */ struct scsi_xfer *xs; /* ... convenience */ int rv; /* Check if recursive dump; if so, punt. */ if (sddoingadump) return EFAULT; if (blkno < 0) return EINVAL; /* Mark as active early. */ sddoingadump = 1; unit = DISKUNIT(dev); /* Decompose unit & partition. */ part = DISKPART(dev); /* Check for acceptable drive number. */ if (unit >= sd_cd.cd_ndevs || (sc = sd_cd.cd_devs[unit]) == NULL) return ENXIO; /* * XXX Can't do this check, since the media might have been * XXX marked `invalid' by successful unmounting of all * XXX filesystems. */ #if 0 /* Make sure it was initialized. */ if ((sc->sc_link->flags & SDEV_MEDIA_LOADED) != SDEV_MEDIA_LOADED) return ENXIO; #endif /* Convert to disk sectors. Request must be a multiple of size. */ lp = sc->sc_dk.dk_label; sectorsize = lp->d_secsize; if ((size % sectorsize) != 0) return EFAULT; if ((blkno % DL_BLKSPERSEC(lp)) != 0) return EFAULT; totwrt = size / sectorsize; blkno = DL_BLKTOSEC(lp, blkno); nsects = DL_GETPSIZE(&lp->d_partitions[part]); sectoff = DL_GETPOFFSET(&lp->d_partitions[part]); /* Check transfer bounds against partition size. */ if ((blkno + totwrt) > nsects) return EINVAL; /* Offset block number to start of partition. */ blkno += sectoff; while (totwrt > 0) { if (totwrt > UINT32_MAX) nwrt = UINT32_MAX; else nwrt = totwrt; #ifndef SD_DUMP_NOT_TRUSTED xs = scsi_xs_get(sc->sc_link, SCSI_NOSLEEP); if (xs == NULL) return (ENOMEM); xs->timeout = 10000; xs->flags |= SCSI_DATA_OUT; xs->data = va; xs->datalen = nwrt * sectorsize; sd_cmd_rw10(xs, 0, blkno, nwrt); /* XXX */ rv = scsi_xs_sync(xs); scsi_xs_put(xs); if (rv != 0) return (ENXIO); #else /* SD_DUMP_NOT_TRUSTED */ /* Let's just talk about this first... */ printf("sd%d: dump addr 0x%x, blk %lld\n", unit, va, (long long)blkno); delay(500 * 1000); /* half a second */ #endif /* SD_DUMP_NOT_TRUSTED */ /* update block count */ totwrt -= nwrt; blkno += nwrt; va += sectorsize * nwrt; } sddoingadump = 0; return (0); }
/* * Search for a VDIT volume information. If one is found, search for a * vdmpart instance of name "OpenBSD". If one is found, set the disklabel * bounds to the area it spans, and attempt to read a native label within * it. */ int readvditlabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp, daddr_t *partoffp, int spoofonly, struct vdm_boot_info *vbi) { struct buf *sbp = NULL; struct vdit_block_header *vbh; struct vdit_entry_header *veh; char *vdit_storage = NULL, *vdit_end; size_t vdit_size; unsigned int largest_chunk, vdit_blkno; int expected_kind; daddr_t blkno; int error = 0; vdit_id_t *vdmpart_id; struct vdit_vdmpart_instance *bsd_vdmpart; /* * Figure out the size of the first VDIT. */ vdit_size = largest_chunk = 0; expected_kind = VDIT_BLOCK_HEAD_BE; blkno = VDIT_SECTOR; for (;;) { error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, blkno)); if (error) return (error); vbh = (struct vdit_block_header *)bp->b_data; if (VDM_ID_KIND(&vbh->id) != expected_kind || VDM_ID_BLKNO(&vbh->id) != vdit_size || vbh->id.node_number != VDM_NO_NODE_NUMBER) return EINVAL; if (vbi != NULL) { if ((blkno >= vbi->boot_start && blkno < vbi->boot_start + vbi->boot_size) || (blkno + vbh->chunksz - 1 >= vbi->boot_start && blkno + vbh->chunksz - 1 < vbi->boot_start + vbi->boot_size)) return EINVAL; } if (vbh->chunksz > largest_chunk) largest_chunk = vbh->chunksz; vdit_size += vbh->chunksz; if (vbh->nextblk == VDM_NO_BLK_NUMBER) break; blkno = vbh->nextblk; if (blkno >= DL_GETDSIZE(lp)) return EINVAL; expected_kind = VDIT_PORTION_HEADER_BLOCK; } /* * Now read the first VDIT. */ vdit_size *= dbtob(1) - sizeof(struct vdit_block_header); vdit_storage = malloc(vdit_size, M_DEVBUF, M_WAITOK); largest_chunk = dbtob(largest_chunk); sbp = geteblk(largest_chunk); sbp->b_dev = bp->b_dev; vdit_end = vdit_storage; expected_kind = VDIT_BLOCK_HEAD_BE; blkno = VDIT_SECTOR; vdit_blkno = 0; for (;;) { sbp->b_blkno = blkno; sbp->b_bcount = largest_chunk; CLR(sbp->b_flags, B_READ | B_WRITE | B_DONE); SET(sbp->b_flags, B_BUSY | B_READ | B_RAW); (*strat)(sbp); if ((error = biowait(sbp)) != 0) goto done; vbh = (struct vdit_block_header *)sbp->b_data; if (VDM_ID_KIND(&vbh->id) != expected_kind) { error = EINVAL; goto done; } vdit_end = extract_vdit_portion(vdit_end, sbp->b_data, vbh->chunksz, vdit_blkno, expected_kind); if (vdit_end == NULL) { error = EINVAL; goto done; } if (vbh->nextblk == VDM_NO_BLK_NUMBER) break; vdit_blkno += vbh->chunksz; blkno = vbh->nextblk; expected_kind = VDIT_PORTION_HEADER_BLOCK; } /* * Walk the VDIT entries. * * If we find an OpenBSD vdmpart, we'll set our disk area bounds to * its area, and will read a label from there. */ vdmpart_id = NULL; bsd_vdmpart = NULL; veh = (struct vdit_entry_header *)vdit_storage; while ((caddr_t)veh < vdit_end) { switch (veh->type) { case VDIT_ENTRY_SUBDRIVER_INFO: { struct vdit_subdriver_entry *vse; vse = (struct vdit_subdriver_entry *)(veh + 1); if (strcmp(vse->name, VDM_SUBDRIVER_VDMPART) == 0) vdmpart_id = &vse->subdriver_id; } break; case VDIT_ENTRY_INSTANCE: { struct vdit_instance_entry *vie; vie = (struct vdit_instance_entry *)(veh + 1); if (strcmp(vie->name, VDM_INSTANCE_OPENBSD) == 0) { if (vdmpart_id != NULL && memcmp(vdmpart_id, &vie->subdriver_id, sizeof(vdit_id_t)) == 0) { /* found it! */ if (bsd_vdmpart != NULL) { bsd_vdmpart = NULL; veh->type = VDIT_ENTRY_SENTINEL; } else bsd_vdmpart = (struct vdit_vdmpart_instance *)vie; } } } break; } if (veh->type == VDIT_ENTRY_SENTINEL) break; veh = (struct vdit_entry_header *)((char *)veh + veh->size); } if (bsd_vdmpart != NULL) { uint32_t start, size; memcpy(&start, &bsd_vdmpart->start_blkno, sizeof(uint32_t)); memcpy(&size, &bsd_vdmpart->size, sizeof(uint32_t)); if (start >= DL_GETDSIZE(lp) || start + size > DL_GETDSIZE(lp)) { error = EINVAL; goto done; } if (partoffp != NULL) { *partoffp = start; goto done; } else { DL_SETBSTART(lp, start); DL_SETBEND(lp, start + size); } /* * Now read the native label. */ if (spoofonly == 0) { error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, start + LABELSECTOR)); if (error) goto done; error = checkdisklabel(bp->b_data + LABELOFFSET, lp, start, start + size); } } else { /* * VDM label, but no OpenBSD vdmpart partition found. * XXX is it worth registering the whole disk as a * XXX `don't touch' vendor partition in that case? */ error = ENOENT; goto done; } done: free(vdit_storage, M_DEVBUF, vdit_size); if (sbp != NULL) { sbp->b_flags |= B_INVAL; brelse(sbp); } return error; }
/* * Search for a VDM "label" (which does not describe any partition). * If one is found, search for either a VDIT label, or a native OpenBSD * label in the first sector. */ int readvdmlabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp, daddr_t *partoffp, int spoofonly) { struct vdm_label *vdl; struct vdm_boot_info *vbi; int error = 0; /* * Read first sector and check for a VDM label. * Note that a VDM label is only required for bootable disks, and * may not be followed by a VDIT. */ error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, VDM_LABEL_SECTOR)); if (error) return (error); vdl = (struct vdm_label *)(bp->b_data + VDM_LABEL_OFFSET); if (vdl->signature != VDM_LABEL_SIGNATURE) vdl = (struct vdm_label *)(bp->b_data + VDM_LABEL_OFFSET_ALT); if (vdl->signature != VDM_LABEL_SIGNATURE) return EINVAL; /* * If the disk is a bootable disk, remember the boot block area, to * be able to check that the VDIT does not overwrite it. */ vbi = (struct vdm_boot_info *)(bp->b_data + dbtob(1) - sizeof *vbi); if (vbi->signature != VDM_LABEL_SIGNATURE || vbi->boot_start == 0) vbi = NULL; if (vbi != NULL && vbi->boot_start == VDIT_SECTOR) return EINVAL; if (vbi != NULL && vbi->boot_start + vbi->boot_size > DL_GETBSTART(lp)) DL_SETBSTART(lp, vbi->boot_start + vbi->boot_size); error = readvditlabel(bp, strat, lp, partoffp, spoofonly, vbi); if (error == 0) return 0; /* * Valid VDIT information, but no OpenBSD vdmpart found. * Do not try to read a native label. */ if (error == ENOENT) return error; if (partoffp != NULL) *partoffp = 0; /* don't read the on-disk label if we are in spoofed-only mode */ if (spoofonly != 0) return 0; error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, LABELSECTOR)); if (error) return (error); return checkdisklabel(bp->b_data + LABELOFFSET, lp, DL_GETBSTART(lp), DL_GETBEND(lp)); }
int readsgilabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp, daddr_t *partoffp, int spoofonly) { struct sgilabel *dlp; int i, *p, cs = 0; daddr_t fsoffs, fsend; int error, offset; /* if successful, locate disk label within block and validate */ error = readdisksector(bp, strat, lp, 0); if (error) return (error); fsoffs = DL_SECTOBLK(lp, DL_GETBSTART(lp)); fsend = DL_SECTOBLK(lp, DL_GETBEND(lp)); dlp = (struct sgilabel *)(bp->b_data + LABELOFFSET); if (dlp->magic != htobe32(SGILABEL_MAGIC)) goto finished; if (dlp->partitions[0].blocks == 0) return (EINVAL); fsoffs = (long long)dlp->partitions[0].first; fsend = fsoffs + dlp->partitions[0].blocks; /* Only came here to find the offset... */ if (partoffp) { *partoffp = fsoffs; goto finished; } p = (int *)dlp; i = sizeof(struct sgilabel) / sizeof(int); while (i--) cs += *p++; if (cs != 0) return (EINVAL); /* sgilabel checksum error */ /* Spoof info from sgi label, in case there is no OpenBSD label. */ lp->d_npartitions = MAXPARTITIONS; for (i = 0; i < 16; i++) { int bsd = maptab[i].m; int type = maptab[i].b; if (spoofonly && type != FS_UNUSED && type != FS_OTHER) continue; DL_SETPOFFSET(&lp->d_partitions[bsd], dlp->partitions[i].first); DL_SETPSIZE(&lp->d_partitions[bsd], dlp->partitions[i].blocks); lp->d_partitions[bsd].p_fstype = type; if (type == FS_BSDFFS) { lp->d_partitions[bsd].p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(1024, 8); lp->d_partitions[bsd].p_cpg = 16; } } DL_SETBSTART(lp, DL_BLKTOSEC(lp, fsoffs)); DL_SETBEND(lp, DL_BLKTOSEC(lp, fsend)); lp->d_version = 1; lp->d_flags = D_VENDOR; lp->d_checksum = 0; lp->d_checksum = dkcksum(lp); finished: /* record the OpenBSD partition's placement for the caller */ if (partoffp) *partoffp = fsoffs; else { DL_SETBSTART(lp, DL_BLKTOSEC(lp, fsoffs)); DL_SETBEND(lp, DL_BLKTOSEC(lp, fsend)); } /* don't read the on-disk label if we are in spoofed-only mode */ if (spoofonly) return (0); error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, fsoffs + LABELSECTOR)); if (error) return (error); offset = DL_BLKOFFSET(lp, fsoffs + LABELSECTOR) + LABELOFFSET; /* * Do OpenBSD disklabel validation/adjustment. * * N.B: No matter what the bits are on the disk, we now have the * OpenBSD disklabel for this sgi disk. DO NOT proceed to * readdoslabel(), iso_spooflabel(), etc. */ checkdisklabel(bp->b_data + offset, lp, fsoffs, fsend); return (0); }
void MBR_init(struct disk *disk, struct mbr *mbr) { daddr_t i; u_int64_t adj; /* Fix up given mbr for this disk */ mbr->part[0].flag = 0; mbr->part[1].flag = 0; mbr->part[2].flag = 0; mbr->part[3].flag = DOSACTIVE; mbr->signature = DOSMBR_SIGNATURE; /* Use whole disk. Reserve first track, or first cyl, if possible. */ mbr->part[3].id = DOSPTYP_OPENBSD; if (disk->real->heads > 1) mbr->part[3].shead = 1; else mbr->part[3].shead = 0; if (disk->real->heads < 2 && disk->real->cylinders > 1) mbr->part[3].scyl = 1; else mbr->part[3].scyl = 0; mbr->part[3].ssect = 1; /* Go right to the end */ mbr->part[3].ecyl = disk->real->cylinders - 1; mbr->part[3].ehead = disk->real->heads - 1; mbr->part[3].esect = disk->real->sectors; /* Fix up start/length fields */ PRT_fix_BN(disk, &mbr->part[3], 3); #if defined(__powerpc__) || defined(__mips__) /* Now fix up for the MS-DOS boot partition on PowerPC. */ mbr->part[0].flag = DOSACTIVE; /* Boot from dos part */ mbr->part[3].flag = 0; mbr->part[3].ns += mbr->part[3].bs; mbr->part[3].bs = mbr->part[0].bs + mbr->part[0].ns; mbr->part[3].ns -= mbr->part[3].bs; PRT_fix_CHS(disk, &mbr->part[3]); if ((mbr->part[3].shead != 1) || (mbr->part[3].ssect != 1)) { /* align the partition on a cylinder boundary */ mbr->part[3].shead = 0; mbr->part[3].ssect = 1; mbr->part[3].scyl += 1; } /* Fix up start/length fields */ PRT_fix_BN(disk, &mbr->part[3], 3); #endif /* Start OpenBSD MBR partition on a power of 2 block number. */ i = 1; while (i < DL_SECTOBLK(&dl, mbr->part[3].bs)) i *= 2; adj = DL_BLKTOSEC(&dl, i) - mbr->part[3].bs; mbr->part[3].bs += adj; mbr->part[3].ns -= adj; PRT_fix_CHS(disk, &mbr->part[3]); }
int readliflabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp, daddr_t *partoffp, int spoofonly) { struct lifdir *p; struct lifvol *lvp; int error = 0; daddr_t fsoff = 0, openbsdstart = MAXLIFSPACE; int i; /* read LIF volume header */ error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, btodb(LIF_VOLSTART))); if (error) return (error); lvp = (struct lifvol *)bp->b_data; if (lvp->vol_id != LIF_VOL_ID) { error = EINVAL; /* no LIF volume header */ goto done; } /* read LIF directory */ error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, lifstodb(lvp->vol_addr))); if (error) goto done; /* scan for LIF_DIR_FS dir entry */ for (i=0, p=(struct lifdir *)bp->b_data; i < LIF_NUMDIR; p++, i++) { if (p->dir_type == LIF_DIR_FS || p->dir_type == LIF_DIR_HPLBL) break; } if (p->dir_type == LIF_DIR_FS) { fsoff = lifstodb(p->dir_addr); openbsdstart = 0; goto finished; } /* Only came here to find the offset... */ if (partoffp) goto finished; if (p->dir_type == LIF_DIR_HPLBL) { struct hpux_label *hl; struct partition *pp; u_int8_t fstype; int i; /* read LIF directory */ error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, lifstodb(p->dir_addr))); if (error) goto done; hl = (struct hpux_label *)bp->b_data; if (hl->hl_magic1 != hl->hl_magic2 || hl->hl_magic != HPUX_MAGIC || hl->hl_version != 1) { error = EINVAL; /* HPUX label magic mismatch */ goto done; } lp->d_bbsize = 8192; lp->d_sbsize = 8192; for (i = 0; i < MAXPARTITIONS; i++) { DL_SETPSIZE(&lp->d_partitions[i], 0); DL_SETPOFFSET(&lp->d_partitions[i], 0); lp->d_partitions[i].p_fstype = 0; } for (i = 0; i < HPUX_MAXPART; i++) { if (!hl->hl_flags[i]) continue; if (hl->hl_flags[i] == HPUX_PART_ROOT) { pp = &lp->d_partitions[0]; fstype = FS_BSDFFS; } else if (hl->hl_flags[i] == HPUX_PART_SWAP) { pp = &lp->d_partitions[1]; fstype = FS_SWAP; } else if (hl->hl_flags[i] == HPUX_PART_BOOT) { pp = &lp->d_partitions[RAW_PART + 1]; fstype = FS_BSDFFS; } else continue; DL_SETPSIZE(pp, hl->hl_parts[i].hlp_length * 2); DL_SETPOFFSET(pp, hl->hl_parts[i].hlp_start * 2); pp->p_fstype = fstype; } DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); DL_SETPOFFSET(&lp->d_partitions[RAW_PART], 0); lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; lp->d_npartitions = MAXPARTITIONS; lp->d_magic = DISKMAGIC; lp->d_magic2 = DISKMAGIC; lp->d_version = 1; lp->d_checksum = 0; lp->d_checksum = dkcksum(lp); /* drop through */ } finished: /* record the OpenBSD partition's placement for the caller */ if (partoffp) *partoffp = fsoff; else { DL_SETBSTART(lp, DL_BLKTOSEC(lp, openbsdstart)); DL_SETBEND(lp, DL_GETDSIZE(lp)); /* XXX */ } /* don't read the on-disk label if we are in spoofed-only mode */ if (spoofonly) goto done; error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, fsoff + LABELSECTOR)); if (error) goto done; /* * Do OpenBSD disklabel validation/adjustment. * * N.B: No matter what the bits are on the disk, we now have the * OpenBSD disklabel for this lif disk. DO NOT proceed to * readdoslabel(), iso_spooflabel(), etc. */ checkdisklabel(bp->b_data, lp, openbsdstart, DL_GETDSIZE(lp)); error = 0; done: return (error); }