/* * 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 (readdpmelabel(bp, strat, lp, &partoff, 1) == 0) { bp->b_blkno = partoff; offset = 0; } else if (readdoslabel(bp, strat, lp, &partoff, 1) == 0) { bp->b_blkno = DL_BLKTOSEC(lp, partoff + DOS_LABELSECTOR) * DL_BLKSPERSEC(lp); offset = DL_BLKOFFSET(lp, partoff + DOS_LABELSECTOR); } else goto done; /* Read it in, slap the new label in, and write it back out */ 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); }
/* * 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); }