subr_disk.c revision 77147
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 77147 2001-05-24 20:27:16Z 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
11277147Sphk	if (proto->d_open != diskopen) {
11351215Sphk		*proto = *cdevsw;
11451215Sphk		proto->d_open = diskopen;
11551215Sphk		proto->d_close = diskclose;
11651215Sphk		proto->d_ioctl = diskioctl;
11751215Sphk		proto->d_strategy = diskstrategy;
11851215Sphk		proto->d_psize = diskpsize;
11950565Sphk	}
12050565Sphk
12153437Sjkh	if (bootverbose)
12253437Sjkh		printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
12351243Sphk	dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
12464880Sphk	    UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit);
12550565Sphk
12650565Sphk	dev->si_disk = dp;
12750565Sphk	dp->d_dev = dev;
12852917Sphk	dp->d_dsflags = flags;
12951215Sphk	dp->d_devsw = cdevsw;
13061717Sphk	LIST_INSERT_HEAD(&disklist, dp, d_list);
13164880Sphk	if (!once) {
13265374Sphk		EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000);
13364880Sphk		once++;
13464880Sphk	}
13550565Sphk	return (dev);
13650565Sphk}
13750565Sphk
13850728Sphkint
13950728Sphkdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
14050728Sphk{
14150728Sphk	struct disk *dp;
14250728Sphk	struct disklabel *dl;
14350728Sphk	u_int boff;
14450728Sphk
14550728Sphk	dp = dev->si_disk;
14650728Sphk	if (!dp)
14750728Sphk		return (ENXIO);
14850728Sphk	if (!dp->d_slice)
14950728Sphk		return (ENXIO);
15050728Sphk	dl = dsgetlabel(dev, dp->d_slice);
15150728Sphk	if (!dl)
15250728Sphk		return (ENXIO);
15350728Sphk	*count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize;
15450728Sphk	if (dumplo < 0 ||
15550728Sphk	    (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
15650728Sphk		return (EINVAL);
15750728Sphk	boff = dl->d_partitions[dkpart(dev)].p_offset +
15850728Sphk	    dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
15950728Sphk	*blkno = boff + dumplo;
16050728Sphk	*secsize = dl->d_secsize;
16150728Sphk	return (0);
16250728Sphk
16350728Sphk}
16450728Sphk
16550728Sphkvoid
16650728Sphkdisk_invalidate (struct disk *disk)
16750728Sphk{
16857325Ssos	if (disk->d_slice)
16957325Ssos		dsgone(&disk->d_slice);
17050728Sphk}
17150728Sphk
17250565Sphkvoid
17356767Sphkdisk_destroy(dev_t dev)
17450565Sphk{
17561717Sphk	LIST_REMOVE(dev->si_disk, d_list);
17661717Sphk	bzero(dev->si_disk, sizeof(*dev->si_disk));
17757325Ssos    	dev->si_disk = NULL;
17857325Ssos	destroy_dev(dev);
17950565Sphk	return;
18050565Sphk}
18150565Sphk
18261717Sphkstruct disk *
18361717Sphkdisk_enumerate(struct disk *disk)
18461717Sphk{
18561717Sphk	if (!disk)
18661717Sphk		return (LIST_FIRST(&disklist));
18761717Sphk	else
18861717Sphk		return (LIST_NEXT(disk, d_list));
18961717Sphk}
19061717Sphk
19161953Snbmstatic int
19262573Sphksysctl_disks(SYSCTL_HANDLER_ARGS)
19361953Snbm{
19461953Snbm	struct disk *disk;
19561953Snbm	int error, first;
19661953Snbm
19761953Snbm	disk = NULL;
19861953Snbm	first = 1;
19961953Snbm
20061953Snbm	while ((disk = disk_enumerate(disk))) {
20161953Snbm		if (!first) {
20261953Snbm			error = SYSCTL_OUT(req, " ", 1);
20361953Snbm			if (error)
20461953Snbm				return error;
20561953Snbm		} else {
20661953Snbm			first = 0;
20761953Snbm		}
20861953Snbm		error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name));
20961953Snbm		if (error)
21061953Snbm			return error;
21161953Snbm	}
21261953Snbm	error = SYSCTL_OUT(req, "", 1);
21361953Snbm	return error;
21461953Snbm}
21561953Snbm
21661953SnbmSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL,
21761953Snbm    sysctl_disks, "A", "names of available disks");
21861953Snbm
21950728Sphk/*
22050728Sphk * The cdevsw functions
22150728Sphk */
22250728Sphk
22350565Sphkstatic int
22450565Sphkdiskopen(dev_t dev, int oflags, int devtype, struct proc *p)
22550565Sphk{
22650565Sphk	dev_t pdev;
22750565Sphk	struct disk *dp;
22850565Sphk	int error;
22950565Sphk
23050728Sphk	error = 0;
23150565Sphk	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
23250728Sphk
23350565Sphk	dp = pdev->si_disk;
23450565Sphk	if (!dp)
23550565Sphk		return (ENXIO);
23650728Sphk
23752917Sphk	while (dp->d_flags & DISKFLAG_LOCK) {
23852917Sphk		dp->d_flags |= DISKFLAG_WANTED;
23954815Sphk		error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
24054815Sphk		if (error)
24154815Sphk			return (error);
24252917Sphk	}
24352917Sphk	dp->d_flags |= DISKFLAG_LOCK;
24452917Sphk
24551860Sphk	if (!dsisopen(dp->d_slice)) {
24651878Ssos		if (!pdev->si_iosize_max)
24751878Ssos			pdev->si_iosize_max = dev->si_iosize_max;
24851826Sphk		error = dp->d_devsw->d_open(pdev, oflags, devtype, p);
24951860Sphk	}
25051826Sphk
25151826Sphk	/* Inherit properties from the whole/raw dev_t */
25262617Simp	inherit_raw(pdev, dev);
25350728Sphk
25450728Sphk	if (error)
25552917Sphk		goto out;
25650728Sphk
25752917Sphk	error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
25850565Sphk
25950728Sphk	if (!dsisopen(dp->d_slice))
26051924Sphk		dp->d_devsw->d_close(pdev, oflags, devtype, p);
26152917Sphkout:
26252917Sphk	dp->d_flags &= ~DISKFLAG_LOCK;
26352917Sphk	if (dp->d_flags & DISKFLAG_WANTED) {
26452917Sphk		dp->d_flags &= ~DISKFLAG_WANTED;
26552917Sphk		wakeup(dp);
26652917Sphk	}
26750728Sphk
26850565Sphk	return(error);
26950565Sphk}
27050565Sphk
27150565Sphkstatic int
27250565Sphkdiskclose(dev_t dev, int fflag, int devtype, struct proc *p)
27350565Sphk{
27450565Sphk	struct disk *dp;
27550565Sphk	int error;
27662617Simp	dev_t pdev;
27750565Sphk
27850565Sphk	error = 0;
27962617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
28062617Simp	dp = pdev->si_disk;
28174206Ssos	if (!dp)
28274206Ssos		return (ENXIO);
28351822Sphk	dsclose(dev, devtype, dp->d_slice);
28474206Ssos	if (!dsisopen(dp->d_slice))
28551924Sphk		error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p);
28650565Sphk	return (error);
28750565Sphk}
28850565Sphk
28950565Sphkstatic void
29059249Sphkdiskstrategy(struct bio *bp)
29150565Sphk{
29250565Sphk	dev_t pdev;
29350565Sphk	struct disk *dp;
29450565Sphk
29562617Simp	pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
29662617Simp	dp = pdev->si_disk;
29776361Sphk	bp->bio_resid = bp->bio_bcount;
29862617Simp	if (dp != bp->bio_dev->si_disk)
29962617Simp		inherit_raw(pdev, bp->bio_dev);
30050565Sphk
30150565Sphk	if (!dp) {
30276322Sphk		biofinish(bp, NULL, ENXIO);
30350565Sphk		return;
30450565Sphk	}
30550565Sphk
30655763Sphk	if (dscheck(bp, dp->d_slice) <= 0) {
30750565Sphk		biodone(bp);
30850565Sphk		return;
30950565Sphk	}
31050565Sphk
31176324Sphk	if (bp->bio_bcount == 0) {
31276324Sphk		biodone(bp);
31376324Sphk		return;
31476324Sphk	}
31576324Sphk
31659623Sphk	KASSERT(dp->d_devsw != NULL, ("NULL devsw"));
31759623Sphk	KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy"));
31851215Sphk	dp->d_devsw->d_strategy(bp);
31950565Sphk	return;
32050565Sphk
32150565Sphk}
32250565Sphk
32350565Sphkstatic int
32450565Sphkdiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
32550565Sphk{
32650565Sphk	struct disk *dp;
32750565Sphk	int error;
32862617Simp	dev_t pdev;
32950565Sphk
33062617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
33162617Simp	dp = pdev->si_disk;
33274206Ssos	if (!dp)
33374206Ssos		return (ENXIO);
33450565Sphk	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
33550565Sphk	if (error == ENOIOCTL)
33651215Sphk		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p);
33750565Sphk	return (error);
33850565Sphk}
33950565Sphk
34050565Sphkstatic int
34150565Sphkdiskpsize(dev_t dev)
34250565Sphk{
34350565Sphk	struct disk *dp;
34450728Sphk	dev_t pdev;
34550565Sphk
34662617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
34762617Simp	dp = pdev->si_disk;
34862617Simp	if (!dp)
34962617Simp		return (-1);
35062617Simp	if (dp != dev->si_disk) {
35150728Sphk		dev->si_drv1 = pdev->si_drv1;
35250728Sphk		dev->si_drv2 = pdev->si_drv2;
35350728Sphk		/* XXX: don't set bp->b_dev->si_disk (?) */
35450728Sphk	}
35550565Sphk	return (dssize(dev, &dp->d_slice));
35650565Sphk}
35751111Sjulian
35851111SjulianSYSCTL_DECL(_debug_sizeof);
35951111Sjulian
36051111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
36151111Sjulian    0, sizeof(struct disklabel), "sizeof(struct disklabel)");
36251111Sjulian
36351111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
36451111Sjulian    0, sizeof(struct diskslices), "sizeof(struct diskslices)");
36551111Sjulian
36651111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
36751111Sjulian    0, sizeof(struct disk), "sizeof(struct disk)");
368