subr_disk.c revision 62617
133965Sjdp/*
289857Sobrien * ----------------------------------------------------------------------------
389857Sobrien * "THE BEER-WARE LICENSE" (Revision 42):
433965Sjdp * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
533965Sjdp * can do whatever you want with this stuff. If we meet some day, and you think
633965Sjdp * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
733965Sjdp * ----------------------------------------------------------------------------
833965Sjdp *
933965Sjdp * $FreeBSD: head/sys/kern/subr_disk.c 62617 2000-07-05 06:01:33Z imp $
1033965Sjdp *
1133965Sjdp */
1233965Sjdp
1333965Sjdp#include <sys/param.h>
1433965Sjdp#include <sys/systm.h>
1533965Sjdp#include <sys/kernel.h>
1633965Sjdp#include <sys/sysctl.h>
1733965Sjdp#include <sys/bio.h>
1833965Sjdp#include <sys/conf.h>
1933965Sjdp#include <sys/disk.h>
2033965Sjdp#include <sys/malloc.h>
2133965Sjdp#include <sys/sysctl.h>
2233965Sjdp#include <machine/md_var.h>
2333965Sjdp
2433965SjdpMALLOC_DEFINE(M_DISK, "disk", "disk data");
2533965Sjdp
2633965Sjdpstatic d_strategy_t diskstrategy;
2733965Sjdpstatic d_open_t diskopen;
2833965Sjdpstatic d_close_t diskclose;
2933965Sjdpstatic d_ioctl_t diskioctl;
3033965Sjdpstatic d_psize_t diskpsize;
3133965Sjdp
3233965Sjdpstatic LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist);
3389857Sobrien
3489857Sobrienstatic void
3589857Sobrieninherit_raw(dev_t pdev, dev_t dev)
3689857Sobrien{
3789857Sobrien	dev->si_disk = pdev->si_disk;
3889857Sobrien	dev->si_drv1 = pdev->si_drv1;
3989857Sobrien	dev->si_drv2 = pdev->si_drv2;
4033965Sjdp	dev->si_iosize_max = pdev->si_iosize_max;
4133965Sjdp	dev->si_bsize_phys = pdev->si_bsize_phys;
4233965Sjdp	dev->si_bsize_best = pdev->si_bsize_best;
4389857Sobrien}
4433965Sjdp
4533965Sjdpdev_t
4633965Sjdpdisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
4733965Sjdp{
4833965Sjdp	dev_t dev;
4933965Sjdp
5033965Sjdp	bzero(dp, sizeof(*dp));
5133965Sjdp
5233965Sjdp	dev = makedev(cdevsw->d_maj, 0);
5333965Sjdp	if (!devsw(dev)) {
5433965Sjdp		*proto = *cdevsw;
5533965Sjdp		proto->d_open = diskopen;
5689857Sobrien		proto->d_close = diskclose;
5733965Sjdp		proto->d_ioctl = diskioctl;
5833965Sjdp		proto->d_strategy = diskstrategy;
5933965Sjdp		proto->d_psize = diskpsize;
6033965Sjdp		cdevsw_add(proto);
6133965Sjdp	}
6233965Sjdp
6333965Sjdp	if (bootverbose)
6433965Sjdp		printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
6533965Sjdp	dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
6633965Sjdp	    0, 0, 0, "%s%d", cdevsw->d_name, unit);
6733965Sjdp
6833965Sjdp	dev->si_disk = dp;
6933965Sjdp	dp->d_dev = dev;
7033965Sjdp	dp->d_dsflags = flags;
7133965Sjdp	dp->d_devsw = cdevsw;
7233965Sjdp	LIST_INSERT_HEAD(&disklist, dp, d_list);
7333965Sjdp	return (dev);
7433965Sjdp}
7533965Sjdp
7633965Sjdpint
7733965Sjdpdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
7833965Sjdp{
7933965Sjdp	struct disk *dp;
8033965Sjdp	struct disklabel *dl;
8133965Sjdp	u_int boff;
8233965Sjdp
8333965Sjdp	dp = dev->si_disk;
8433965Sjdp	if (!dp)
8589857Sobrien		return (ENXIO);
8633965Sjdp	if (!dp->d_slice)
8789857Sobrien		return (ENXIO);
8889857Sobrien	dl = dsgetlabel(dev, dp->d_slice);
8933965Sjdp	if (!dl)
9033965Sjdp		return (ENXIO);
9133965Sjdp	*count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize;
9233965Sjdp	if (dumplo < 0 ||
9333965Sjdp	    (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
9433965Sjdp		return (EINVAL);
9533965Sjdp	boff = dl->d_partitions[dkpart(dev)].p_offset +
9689857Sobrien	    dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
9733965Sjdp	*blkno = boff + dumplo;
9833965Sjdp	*secsize = dl->d_secsize;
9933965Sjdp	return (0);
10033965Sjdp
10133965Sjdp}
10233965Sjdp
10333965Sjdpvoid
10433965Sjdpdisk_invalidate (struct disk *disk)
10533965Sjdp{
10633965Sjdp	if (disk->d_slice)
10733965Sjdp		dsgone(&disk->d_slice);
10889857Sobrien}
10989857Sobrien
11033965Sjdpvoid
11133965Sjdpdisk_destroy(dev_t dev)
11233965Sjdp{
11333965Sjdp	LIST_REMOVE(dev->si_disk, d_list);
11433965Sjdp	bzero(dev->si_disk, sizeof(*dev->si_disk));
11533965Sjdp    	dev->si_disk = NULL;
11633965Sjdp	destroy_dev(dev);
11733965Sjdp	return;
11833965Sjdp}
11933965Sjdp
12033965Sjdpstruct disk *
12133965Sjdpdisk_enumerate(struct disk *disk)
12233965Sjdp{
12333965Sjdp	if (!disk)
12433965Sjdp		return (LIST_FIRST(&disklist));
12533965Sjdp	else
12633965Sjdp		return (LIST_NEXT(disk, d_list));
12733965Sjdp}
12833965Sjdp
12933965Sjdpstatic int
13033965Sjdpsysctl_disks(SYSCTL_HANDLER_ARGS)
13133965Sjdp{
13260484Sobrien	struct disk *disk;
13333965Sjdp	int error, first;
13433965Sjdp
13533965Sjdp	disk = NULL;
13633965Sjdp	first = 1;
13733965Sjdp
13833965Sjdp	while ((disk = disk_enumerate(disk))) {
13933965Sjdp		if (!first) {
14033965Sjdp			error = SYSCTL_OUT(req, " ", 1);
14189857Sobrien			if (error)
14233965Sjdp				return error;
14333965Sjdp		} else {
14433965Sjdp			first = 0;
14533965Sjdp		}
14633965Sjdp		error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name));
14789857Sobrien		if (error)
14889857Sobrien			return error;
14989857Sobrien	}
15089857Sobrien	error = SYSCTL_OUT(req, "", 1);
15189857Sobrien	return error;
15289857Sobrien}
15333965Sjdp
15433965SjdpSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL,
15533965Sjdp    sysctl_disks, "A", "names of available disks");
15633965Sjdp
15733965Sjdp/*
15833965Sjdp * The cdevsw functions
15933965Sjdp */
16033965Sjdp
16133965Sjdpstatic int
16233965Sjdpdiskopen(dev_t dev, int oflags, int devtype, struct proc *p)
16333965Sjdp{
16433965Sjdp	dev_t pdev;
16533965Sjdp	struct disk *dp;
16633965Sjdp	int error;
16733965Sjdp
16833965Sjdp	error = 0;
16933965Sjdp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
17033965Sjdp
17133965Sjdp	dp = pdev->si_disk;
17233965Sjdp	if (!dp)
17389857Sobrien		return (ENXIO);
17489857Sobrien
17533965Sjdp	while (dp->d_flags & DISKFLAG_LOCK) {
17633965Sjdp		dp->d_flags |= DISKFLAG_WANTED;
17733965Sjdp		error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
17833965Sjdp		if (error)
17933965Sjdp			return (error);
18033965Sjdp	}
18133965Sjdp	dp->d_flags |= DISKFLAG_LOCK;
18233965Sjdp
18333965Sjdp	if (!dsisopen(dp->d_slice)) {
18433965Sjdp		if (!pdev->si_iosize_max)
18533965Sjdp			pdev->si_iosize_max = dev->si_iosize_max;
18633965Sjdp		error = dp->d_devsw->d_open(pdev, oflags, devtype, p);
18733965Sjdp	}
18833965Sjdp
18933965Sjdp	/* Inherit properties from the whole/raw dev_t */
19033965Sjdp	inherit_raw(pdev, dev);
19133965Sjdp
19233965Sjdp	if (error)
19333965Sjdp		goto out;
19433965Sjdp
19533965Sjdp	error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
19633965Sjdp
19733965Sjdp	if (!dsisopen(dp->d_slice))
19833965Sjdp		dp->d_devsw->d_close(pdev, oflags, devtype, p);
19933965Sjdpout:
20033965Sjdp	dp->d_flags &= ~DISKFLAG_LOCK;
20133965Sjdp	if (dp->d_flags & DISKFLAG_WANTED) {
20233965Sjdp		dp->d_flags &= ~DISKFLAG_WANTED;
20333965Sjdp		wakeup(dp);
20433965Sjdp	}
20533965Sjdp
20633965Sjdp	return(error);
20733965Sjdp}
20833965Sjdp
20933965Sjdpstatic int
21033965Sjdpdiskclose(dev_t dev, int fflag, int devtype, struct proc *p)
21133965Sjdp{
21233965Sjdp	struct disk *dp;
21333965Sjdp	int error;
21433965Sjdp	dev_t pdev;
21533965Sjdp
21633965Sjdp	error = 0;
21733965Sjdp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
21833965Sjdp	dp = pdev->si_disk;
21933965Sjdp	dsclose(dev, devtype, dp->d_slice);
22033965Sjdp	if (!dsisopen(dp->d_slice)) {
22133965Sjdp		error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p);
22233965Sjdp	}
22333965Sjdp	return (error);
22433965Sjdp}
22589857Sobrien
22689857Sobrienstatic void
22789857Sobriendiskstrategy(struct bio *bp)
22889857Sobrien{
22989857Sobrien	dev_t pdev;
23089857Sobrien	struct disk *dp;
23189857Sobrien
23289857Sobrien	pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
23389857Sobrien	dp = pdev->si_disk;
23489857Sobrien	if (dp != bp->bio_dev->si_disk)
23560484Sobrien		inherit_raw(pdev, bp->bio_dev);
23689857Sobrien
23733965Sjdp	if (!dp) {
23833965Sjdp		bp->bio_error = ENXIO;
239		bp->bio_flags |= BIO_ERROR;
240		biodone(bp);
241		return;
242	}
243
244	if (dscheck(bp, dp->d_slice) <= 0) {
245		biodone(bp);
246		return;
247	}
248
249	KASSERT(dp->d_devsw != NULL, ("NULL devsw"));
250	KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy"));
251	dp->d_devsw->d_strategy(bp);
252	return;
253
254}
255
256static int
257diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
258{
259	struct disk *dp;
260	int error;
261	dev_t pdev;
262
263	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
264	dp = pdev->si_disk;
265	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
266	if (error == ENOIOCTL)
267		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p);
268	return (error);
269}
270
271static int
272diskpsize(dev_t dev)
273{
274	struct disk *dp;
275	dev_t pdev;
276
277	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
278	dp = pdev->si_disk;
279	if (!dp)
280		return (-1);
281	if (dp != dev->si_disk) {
282		dev->si_drv1 = pdev->si_drv1;
283		dev->si_drv2 = pdev->si_drv2;
284		/* XXX: don't set bp->b_dev->si_disk (?) */
285	}
286	return (dssize(dev, &dp->d_slice));
287}
288
289SYSCTL_DECL(_debug_sizeof);
290
291SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
292    0, sizeof(struct disklabel), "sizeof(struct disklabel)");
293
294SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
295    0, sizeof(struct diskslices), "sizeof(struct diskslices)");
296
297SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
298    0, sizeof(struct disk), "sizeof(struct disk)");
299