subr_disk.c revision 76361
150565Sphk/*
250565Sphk * ----------------------------------------------------------------------------
350565Sphk * "THE BEER-WARE LICENSE" (Revision 42):
450565Sphk * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
550565Sphk * can do whatever you want with this stuff. If we meet some day, and you think
650565Sphk * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
750565Sphk * ----------------------------------------------------------------------------
850565Sphk *
950565Sphk * $FreeBSD: head/sys/kern/subr_disk.c 76361 2001-05-08 08:24:54Z phk $
1050565Sphk *
1150565Sphk */
1250565Sphk
1350565Sphk#include <sys/param.h>
1450565Sphk#include <sys/systm.h>
1550565Sphk#include <sys/kernel.h>
1651111Sjulian#include <sys/sysctl.h>
1760041Sphk#include <sys/bio.h>
1850565Sphk#include <sys/conf.h>
1950565Sphk#include <sys/disk.h>
2050565Sphk#include <sys/malloc.h>
2161953Snbm#include <sys/sysctl.h>
2250728Sphk#include <machine/md_var.h>
2364880Sphk#include <sys/ctype.h>
2464880Sphk
2569774Sphkstatic MALLOC_DEFINE(M_DISK, "disk", "disk data");
2650565Sphk
2750565Sphkstatic d_strategy_t diskstrategy;
2850565Sphkstatic d_open_t diskopen;
2950565Sphkstatic d_close_t diskclose;
3050565Sphkstatic d_ioctl_t diskioctl;
3150565Sphkstatic d_psize_t diskpsize;
3261717Sphk
3361717Sphkstatic LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist);
3464880Sphk
3562617Simpstatic void
3664880Sphkdisk_clone(void *arg, char *name, int namelen, dev_t *dev)
3764880Sphk{
3864880Sphk	struct disk *dp;
3964880Sphk	char const *d;
4064880Sphk	int i, u, s, p;
4164880Sphk	dev_t pdev;
4264880Sphk
4364880Sphk	if (*dev != NODEV)
4464880Sphk		return;
4564880Sphk
4664880Sphk	LIST_FOREACH(dp, &disklist, d_list) {
4764880Sphk		d = dp->d_devsw->d_name;
4864880Sphk		i = strlen(d);
4964880Sphk		if (bcmp(d, name, i) != 0)
5064880Sphk			continue;
5164880Sphk		u = 0;
5264880Sphk		if (!isdigit(name[i]))
5364880Sphk			continue;
5464880Sphk		while (isdigit(name[i])) {
5564880Sphk			u *= 10;
5664880Sphk			u += name[i++] - '0';
5764880Sphk		}
5870058Sphk		if (u > DKMAXUNIT)
5970058Sphk			continue;
6064880Sphk		p = RAW_PART;
6164880Sphk		s = WHOLE_DISK_SLICE;
6264880Sphk		pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p));
6364880Sphk		if (pdev->si_disk == NULL)
6464880Sphk			continue;
6564880Sphk		if (name[i] != '\0') {
6664880Sphk			if (name[i] == 's') {
6764880Sphk				s = 0;
6864880Sphk				i++;
6964880Sphk				if (!isdigit(name[i]))
7064880Sphk					continue;
7164880Sphk				while (isdigit(name[i])) {
7264880Sphk					s *= 10;
7364880Sphk					s += name[i++] - '0';
7464880Sphk				}
7564880Sphk				s += BASE_SLICE - 1;
7664880Sphk			} else {
7764880Sphk				s = COMPATIBILITY_SLICE;
7864880Sphk			}
7964880Sphk			if (name[i] == '\0')
8064880Sphk				;
8164880Sphk			else if (name[i] < 'a' || name[i] > 'h')
8264880Sphk				continue;
8364880Sphk			else
8464880Sphk				p = name[i] - 'a';
8564880Sphk		}
8664880Sphk
8764880Sphk		*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
8864880Sphk		    UID_ROOT, GID_OPERATOR, 0640, name);
8964880Sphk		return;
9064880Sphk	}
9164880Sphk}
9264880Sphk
9364880Sphkstatic void
9462617Simpinherit_raw(dev_t pdev, dev_t dev)
9562617Simp{
9662617Simp	dev->si_disk = pdev->si_disk;
9762617Simp	dev->si_drv1 = pdev->si_drv1;
9862617Simp	dev->si_drv2 = pdev->si_drv2;
9962617Simp	dev->si_iosize_max = pdev->si_iosize_max;
10062617Simp	dev->si_bsize_phys = pdev->si_bsize_phys;
10162617Simp	dev->si_bsize_best = pdev->si_bsize_best;
10262617Simp}
10362617Simp
10450565Sphkdev_t
10551215Sphkdisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
10650565Sphk{
10764880Sphk	static int once;
10850565Sphk	dev_t dev;
10950565Sphk
11051198Sphk	bzero(dp, sizeof(*dp));
11151198Sphk
11250565Sphk	dev = makedev(cdevsw->d_maj, 0);
11351198Sphk	if (!devsw(dev)) {
11451215Sphk		*proto = *cdevsw;
11551215Sphk		proto->d_open = diskopen;
11651215Sphk		proto->d_close = diskclose;
11751215Sphk		proto->d_ioctl = diskioctl;
11851215Sphk		proto->d_strategy = diskstrategy;
11951215Sphk		proto->d_psize = diskpsize;
12051215Sphk		cdevsw_add(proto);
12150565Sphk	}
12250565Sphk
12353437Sjkh	if (bootverbose)
12453437Sjkh		printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
12551243Sphk	dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
12664880Sphk	    UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit);
12750565Sphk
12850565Sphk	dev->si_disk = dp;
12950565Sphk	dp->d_dev = dev;
13052917Sphk	dp->d_dsflags = flags;
13151215Sphk	dp->d_devsw = cdevsw;
13261717Sphk	LIST_INSERT_HEAD(&disklist, dp, d_list);
13364880Sphk	if (!once) {
13465374Sphk		EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000);
13564880Sphk		once++;
13664880Sphk	}
13750565Sphk	return (dev);
13850565Sphk}
13950565Sphk
14050728Sphkint
14150728Sphkdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
14250728Sphk{
14350728Sphk	struct disk *dp;
14450728Sphk	struct disklabel *dl;
14550728Sphk	u_int boff;
14650728Sphk
14750728Sphk	dp = dev->si_disk;
14850728Sphk	if (!dp)
14950728Sphk		return (ENXIO);
15050728Sphk	if (!dp->d_slice)
15150728Sphk		return (ENXIO);
15250728Sphk	dl = dsgetlabel(dev, dp->d_slice);
15350728Sphk	if (!dl)
15450728Sphk		return (ENXIO);
15550728Sphk	*count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize;
15650728Sphk	if (dumplo < 0 ||
15750728Sphk	    (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
15850728Sphk		return (EINVAL);
15950728Sphk	boff = dl->d_partitions[dkpart(dev)].p_offset +
16050728Sphk	    dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
16150728Sphk	*blkno = boff + dumplo;
16250728Sphk	*secsize = dl->d_secsize;
16350728Sphk	return (0);
16450728Sphk
16550728Sphk}
16650728Sphk
16750728Sphkvoid
16850728Sphkdisk_invalidate (struct disk *disk)
16950728Sphk{
17057325Ssos	if (disk->d_slice)
17157325Ssos		dsgone(&disk->d_slice);
17250728Sphk}
17350728Sphk
17450565Sphkvoid
17556767Sphkdisk_destroy(dev_t dev)
17650565Sphk{
17761717Sphk	LIST_REMOVE(dev->si_disk, d_list);
17861717Sphk	bzero(dev->si_disk, sizeof(*dev->si_disk));
17957325Ssos    	dev->si_disk = NULL;
18057325Ssos	destroy_dev(dev);
18150565Sphk	return;
18250565Sphk}
18350565Sphk
18461717Sphkstruct disk *
18561717Sphkdisk_enumerate(struct disk *disk)
18661717Sphk{
18761717Sphk	if (!disk)
18861717Sphk		return (LIST_FIRST(&disklist));
18961717Sphk	else
19061717Sphk		return (LIST_NEXT(disk, d_list));
19161717Sphk}
19261717Sphk
19361953Snbmstatic int
19462573Sphksysctl_disks(SYSCTL_HANDLER_ARGS)
19561953Snbm{
19661953Snbm	struct disk *disk;
19761953Snbm	int error, first;
19861953Snbm
19961953Snbm	disk = NULL;
20061953Snbm	first = 1;
20161953Snbm
20261953Snbm	while ((disk = disk_enumerate(disk))) {
20361953Snbm		if (!first) {
20461953Snbm			error = SYSCTL_OUT(req, " ", 1);
20561953Snbm			if (error)
20661953Snbm				return error;
20761953Snbm		} else {
20861953Snbm			first = 0;
20961953Snbm		}
21061953Snbm		error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name));
21161953Snbm		if (error)
21261953Snbm			return error;
21361953Snbm	}
21461953Snbm	error = SYSCTL_OUT(req, "", 1);
21561953Snbm	return error;
21661953Snbm}
21761953Snbm
21861953SnbmSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL,
21961953Snbm    sysctl_disks, "A", "names of available disks");
22061953Snbm
22150728Sphk/*
22250728Sphk * The cdevsw functions
22350728Sphk */
22450728Sphk
22550565Sphkstatic int
22650565Sphkdiskopen(dev_t dev, int oflags, int devtype, struct proc *p)
22750565Sphk{
22850565Sphk	dev_t pdev;
22950565Sphk	struct disk *dp;
23050565Sphk	int error;
23150565Sphk
23250728Sphk	error = 0;
23350565Sphk	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
23450728Sphk
23550565Sphk	dp = pdev->si_disk;
23650565Sphk	if (!dp)
23750565Sphk		return (ENXIO);
23850728Sphk
23952917Sphk	while (dp->d_flags & DISKFLAG_LOCK) {
24052917Sphk		dp->d_flags |= DISKFLAG_WANTED;
24154815Sphk		error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
24254815Sphk		if (error)
24354815Sphk			return (error);
24452917Sphk	}
24552917Sphk	dp->d_flags |= DISKFLAG_LOCK;
24652917Sphk
24751860Sphk	if (!dsisopen(dp->d_slice)) {
24851878Ssos		if (!pdev->si_iosize_max)
24951878Ssos			pdev->si_iosize_max = dev->si_iosize_max;
25051826Sphk		error = dp->d_devsw->d_open(pdev, oflags, devtype, p);
25151860Sphk	}
25251826Sphk
25351826Sphk	/* Inherit properties from the whole/raw dev_t */
25462617Simp	inherit_raw(pdev, dev);
25550728Sphk
25650728Sphk	if (error)
25752917Sphk		goto out;
25850728Sphk
25952917Sphk	error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
26050565Sphk
26150728Sphk	if (!dsisopen(dp->d_slice))
26251924Sphk		dp->d_devsw->d_close(pdev, oflags, devtype, p);
26352917Sphkout:
26452917Sphk	dp->d_flags &= ~DISKFLAG_LOCK;
26552917Sphk	if (dp->d_flags & DISKFLAG_WANTED) {
26652917Sphk		dp->d_flags &= ~DISKFLAG_WANTED;
26752917Sphk		wakeup(dp);
26852917Sphk	}
26950728Sphk
27050565Sphk	return(error);
27150565Sphk}
27250565Sphk
27350565Sphkstatic int
27450565Sphkdiskclose(dev_t dev, int fflag, int devtype, struct proc *p)
27550565Sphk{
27650565Sphk	struct disk *dp;
27750565Sphk	int error;
27862617Simp	dev_t pdev;
27950565Sphk
28050565Sphk	error = 0;
28162617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
28262617Simp	dp = pdev->si_disk;
28374206Ssos	if (!dp)
28474206Ssos		return (ENXIO);
28551822Sphk	dsclose(dev, devtype, dp->d_slice);
28674206Ssos	if (!dsisopen(dp->d_slice))
28751924Sphk		error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p);
28850565Sphk	return (error);
28950565Sphk}
29050565Sphk
29150565Sphkstatic void
29259249Sphkdiskstrategy(struct bio *bp)
29350565Sphk{
29450565Sphk	dev_t pdev;
29550565Sphk	struct disk *dp;
29650565Sphk
29762617Simp	pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
29862617Simp	dp = pdev->si_disk;
29976361Sphk	bp->bio_resid = bp->bio_bcount;
30062617Simp	if (dp != bp->bio_dev->si_disk)
30162617Simp		inherit_raw(pdev, bp->bio_dev);
30250565Sphk
30350565Sphk	if (!dp) {
30476322Sphk		biofinish(bp, NULL, ENXIO);
30550565Sphk		return;
30650565Sphk	}
30750565Sphk
30855763Sphk	if (dscheck(bp, dp->d_slice) <= 0) {
30950565Sphk		biodone(bp);
31050565Sphk		return;
31150565Sphk	}
31250565Sphk
31376324Sphk	if (bp->bio_bcount == 0) {
31476324Sphk		biodone(bp);
31576324Sphk		return;
31676324Sphk	}
31776324Sphk
31859623Sphk	KASSERT(dp->d_devsw != NULL, ("NULL devsw"));
31959623Sphk	KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy"));
32051215Sphk	dp->d_devsw->d_strategy(bp);
32150565Sphk	return;
32250565Sphk
32350565Sphk}
32450565Sphk
32550565Sphkstatic int
32650565Sphkdiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
32750565Sphk{
32850565Sphk	struct disk *dp;
32950565Sphk	int error;
33062617Simp	dev_t pdev;
33150565Sphk
33262617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
33362617Simp	dp = pdev->si_disk;
33474206Ssos	if (!dp)
33574206Ssos		return (ENXIO);
33650565Sphk	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
33750565Sphk	if (error == ENOIOCTL)
33851215Sphk		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p);
33950565Sphk	return (error);
34050565Sphk}
34150565Sphk
34250565Sphkstatic int
34350565Sphkdiskpsize(dev_t dev)
34450565Sphk{
34550565Sphk	struct disk *dp;
34650728Sphk	dev_t pdev;
34750565Sphk
34862617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
34962617Simp	dp = pdev->si_disk;
35062617Simp	if (!dp)
35162617Simp		return (-1);
35262617Simp	if (dp != dev->si_disk) {
35350728Sphk		dev->si_drv1 = pdev->si_drv1;
35450728Sphk		dev->si_drv2 = pdev->si_drv2;
35550728Sphk		/* XXX: don't set bp->b_dev->si_disk (?) */
35650728Sphk	}
35750565Sphk	return (dssize(dev, &dp->d_slice));
35850565Sphk}
35951111Sjulian
36051111SjulianSYSCTL_DECL(_debug_sizeof);
36151111Sjulian
36251111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
36351111Sjulian    0, sizeof(struct disklabel), "sizeof(struct disklabel)");
36451111Sjulian
36551111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
36651111Sjulian    0, sizeof(struct diskslices), "sizeof(struct diskslices)");
36751111Sjulian
36851111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
36951111Sjulian    0, sizeof(struct disk), "sizeof(struct disk)");
370