Exemplo n.º 1
0
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);
}
Exemplo n.º 2
0
/*
 * 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);
}
Exemplo n.º 3
0
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()");
	}
}
Exemplo n.º 4
0
/*
 * 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);
}
Exemplo n.º 5
0
/*
 * 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);
}
Exemplo n.º 6
0
/*
 * 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);
}
Exemplo n.º 7
0
/*
 * 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);
}
Exemplo n.º 8
0
/*
 * 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);
}
Exemplo n.º 9
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;
}
Exemplo n.º 10
0
/*
 * 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));
}
Exemplo n.º 11
0
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);
}
Exemplo n.º 12
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]);
}
Exemplo n.º 13
0
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);
}