subr_disk.c revision 83366
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 83366 2001-09-12 08:38:13Z julian $
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);
8977215Sphk		dev_depends(pdev, *dev);
9064880Sphk		return;
9164880Sphk	}
9264880Sphk}
9364880Sphk
9464880Sphkstatic void
9562617Simpinherit_raw(dev_t pdev, dev_t dev)
9662617Simp{
9762617Simp	dev->si_disk = pdev->si_disk;
9862617Simp	dev->si_drv1 = pdev->si_drv1;
9962617Simp	dev->si_drv2 = pdev->si_drv2;
10062617Simp	dev->si_iosize_max = pdev->si_iosize_max;
10162617Simp	dev->si_bsize_phys = pdev->si_bsize_phys;
10262617Simp	dev->si_bsize_best = pdev->si_bsize_best;
10362617Simp}
10462617Simp
10550565Sphkdev_t
10651215Sphkdisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
10750565Sphk{
10864880Sphk	static int once;
10977408Sphk	dev_t dev;
11050565Sphk
11177215Sphk	if (!once) {
11277215Sphk		EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000);
11377215Sphk		once++;
11477215Sphk	}
11577215Sphk
11651198Sphk	bzero(dp, sizeof(*dp));
11751198Sphk
11877147Sphk	if (proto->d_open != diskopen) {
11951215Sphk		*proto = *cdevsw;
12051215Sphk		proto->d_open = diskopen;
12151215Sphk		proto->d_close = diskclose;
12251215Sphk		proto->d_ioctl = diskioctl;
12351215Sphk		proto->d_strategy = diskstrategy;
12451215Sphk		proto->d_psize = diskpsize;
12577343Sphk		cdevsw_add(proto);
12650565Sphk	}
12750565Sphk
12853437Sjkh	if (bootverbose)
12953437Sjkh		printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
13051243Sphk	dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
13164880Sphk	    UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit);
13250565Sphk
13350565Sphk	dev->si_disk = dp;
13450565Sphk	dp->d_dev = dev;
13552917Sphk	dp->d_dsflags = flags;
13651215Sphk	dp->d_devsw = cdevsw;
13761717Sphk	LIST_INSERT_HEAD(&disklist, dp, d_list);
13877215Sphk
13950565Sphk	return (dev);
14050565Sphk}
14150565Sphk
14250728Sphkint
14350728Sphkdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
14450728Sphk{
14550728Sphk	struct disk *dp;
14650728Sphk	struct disklabel *dl;
14750728Sphk	u_int boff;
14850728Sphk
14950728Sphk	dp = dev->si_disk;
15050728Sphk	if (!dp)
15150728Sphk		return (ENXIO);
15250728Sphk	if (!dp->d_slice)
15350728Sphk		return (ENXIO);
15450728Sphk	dl = dsgetlabel(dev, dp->d_slice);
15550728Sphk	if (!dl)
15650728Sphk		return (ENXIO);
15781688Sbde	*count = Maxmem * (PAGE_SIZE / dl->d_secsize);
15881688Sbde	if (dumplo <= LABELSECTOR ||
15950728Sphk	    (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
16050728Sphk		return (EINVAL);
16150728Sphk	boff = dl->d_partitions[dkpart(dev)].p_offset +
16250728Sphk	    dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
16350728Sphk	*blkno = boff + dumplo;
16450728Sphk	*secsize = dl->d_secsize;
16550728Sphk	return (0);
16650728Sphk
16750728Sphk}
16850728Sphk
16950728Sphkvoid
17050728Sphkdisk_invalidate (struct disk *disk)
17150728Sphk{
17257325Ssos	if (disk->d_slice)
17357325Ssos		dsgone(&disk->d_slice);
17450728Sphk}
17550728Sphk
17650565Sphkvoid
17756767Sphkdisk_destroy(dev_t dev)
17850565Sphk{
17961717Sphk	LIST_REMOVE(dev->si_disk, d_list);
18061717Sphk	bzero(dev->si_disk, sizeof(*dev->si_disk));
18157325Ssos    	dev->si_disk = NULL;
18257325Ssos	destroy_dev(dev);
18350565Sphk	return;
18450565Sphk}
18550565Sphk
18661717Sphkstruct disk *
18761717Sphkdisk_enumerate(struct disk *disk)
18861717Sphk{
18961717Sphk	if (!disk)
19061717Sphk		return (LIST_FIRST(&disklist));
19161717Sphk	else
19261717Sphk		return (LIST_NEXT(disk, d_list));
19361717Sphk}
19461717Sphk
19561953Snbmstatic int
19662573Sphksysctl_disks(SYSCTL_HANDLER_ARGS)
19761953Snbm{
19861953Snbm	struct disk *disk;
19961953Snbm	int error, first;
20061953Snbm
20161953Snbm	disk = NULL;
20261953Snbm	first = 1;
20361953Snbm
20461953Snbm	while ((disk = disk_enumerate(disk))) {
20561953Snbm		if (!first) {
20661953Snbm			error = SYSCTL_OUT(req, " ", 1);
20761953Snbm			if (error)
20861953Snbm				return error;
20961953Snbm		} else {
21061953Snbm			first = 0;
21161953Snbm		}
21261953Snbm		error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name));
21361953Snbm		if (error)
21461953Snbm			return error;
21561953Snbm	}
21661953Snbm	error = SYSCTL_OUT(req, "", 1);
21761953Snbm	return error;
21861953Snbm}
21961953Snbm
22061953SnbmSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL,
22161953Snbm    sysctl_disks, "A", "names of available disks");
22261953Snbm
22350728Sphk/*
22450728Sphk * The cdevsw functions
22550728Sphk */
22650728Sphk
22750565Sphkstatic int
22883366Sjuliandiskopen(dev_t dev, int oflags, int devtype, struct thread *td)
22950565Sphk{
23050565Sphk	dev_t pdev;
23150565Sphk	struct disk *dp;
23250565Sphk	int error;
23350565Sphk
23450728Sphk	error = 0;
23550565Sphk	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
23650728Sphk
23750565Sphk	dp = pdev->si_disk;
23850565Sphk	if (!dp)
23950565Sphk		return (ENXIO);
24050728Sphk
24152917Sphk	while (dp->d_flags & DISKFLAG_LOCK) {
24252917Sphk		dp->d_flags |= DISKFLAG_WANTED;
24354815Sphk		error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
24454815Sphk		if (error)
24554815Sphk			return (error);
24652917Sphk	}
24752917Sphk	dp->d_flags |= DISKFLAG_LOCK;
24852917Sphk
24951860Sphk	if (!dsisopen(dp->d_slice)) {
25051878Ssos		if (!pdev->si_iosize_max)
25151878Ssos			pdev->si_iosize_max = dev->si_iosize_max;
25283366Sjulian		error = dp->d_devsw->d_open(pdev, oflags, devtype, td);
25351860Sphk	}
25451826Sphk
25551826Sphk	/* Inherit properties from the whole/raw dev_t */
25662617Simp	inherit_raw(pdev, dev);
25750728Sphk
25850728Sphk	if (error)
25952917Sphk		goto out;
26050728Sphk
26152917Sphk	error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
26250565Sphk
26350728Sphk	if (!dsisopen(dp->d_slice))
26483366Sjulian		dp->d_devsw->d_close(pdev, oflags, devtype, td);
26552917Sphkout:
26652917Sphk	dp->d_flags &= ~DISKFLAG_LOCK;
26752917Sphk	if (dp->d_flags & DISKFLAG_WANTED) {
26852917Sphk		dp->d_flags &= ~DISKFLAG_WANTED;
26952917Sphk		wakeup(dp);
27052917Sphk	}
27150728Sphk
27250565Sphk	return(error);
27350565Sphk}
27450565Sphk
27550565Sphkstatic int
27683366Sjuliandiskclose(dev_t dev, int fflag, int devtype, struct thread *td)
27750565Sphk{
27850565Sphk	struct disk *dp;
27950565Sphk	int error;
28062617Simp	dev_t pdev;
28150565Sphk
28250565Sphk	error = 0;
28362617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
28462617Simp	dp = pdev->si_disk;
28574206Ssos	if (!dp)
28674206Ssos		return (ENXIO);
28751822Sphk	dsclose(dev, devtype, dp->d_slice);
28874206Ssos	if (!dsisopen(dp->d_slice))
28983366Sjulian		error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td);
29050565Sphk	return (error);
29150565Sphk}
29250565Sphk
29350565Sphkstatic void
29459249Sphkdiskstrategy(struct bio *bp)
29550565Sphk{
29650565Sphk	dev_t pdev;
29750565Sphk	struct disk *dp;
29850565Sphk
29962617Simp	pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
30062617Simp	dp = pdev->si_disk;
30176361Sphk	bp->bio_resid = bp->bio_bcount;
30262617Simp	if (dp != bp->bio_dev->si_disk)
30362617Simp		inherit_raw(pdev, bp->bio_dev);
30450565Sphk
30550565Sphk	if (!dp) {
30676322Sphk		biofinish(bp, NULL, ENXIO);
30750565Sphk		return;
30850565Sphk	}
30950565Sphk
31055763Sphk	if (dscheck(bp, dp->d_slice) <= 0) {
31150565Sphk		biodone(bp);
31250565Sphk		return;
31350565Sphk	}
31450565Sphk
31576324Sphk	if (bp->bio_bcount == 0) {
31676324Sphk		biodone(bp);
31776324Sphk		return;
31876324Sphk	}
31976324Sphk
32059623Sphk	KASSERT(dp->d_devsw != NULL, ("NULL devsw"));
32159623Sphk	KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy"));
32251215Sphk	dp->d_devsw->d_strategy(bp);
32350565Sphk	return;
32450565Sphk
32550565Sphk}
32650565Sphk
32750565Sphkstatic int
32883366Sjuliandiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
32950565Sphk{
33050565Sphk	struct disk *dp;
33150565Sphk	int error;
33262617Simp	dev_t pdev;
33350565Sphk
33462617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
33562617Simp	dp = pdev->si_disk;
33674206Ssos	if (!dp)
33774206Ssos		return (ENXIO);
33850565Sphk	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
33950565Sphk	if (error == ENOIOCTL)
34083366Sjulian		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td);
34150565Sphk	return (error);
34250565Sphk}
34350565Sphk
34450565Sphkstatic int
34550565Sphkdiskpsize(dev_t dev)
34650565Sphk{
34750565Sphk	struct disk *dp;
34850728Sphk	dev_t pdev;
34950565Sphk
35062617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
35162617Simp	dp = pdev->si_disk;
35262617Simp	if (!dp)
35362617Simp		return (-1);
35462617Simp	if (dp != dev->si_disk) {
35550728Sphk		dev->si_drv1 = pdev->si_drv1;
35650728Sphk		dev->si_drv2 = pdev->si_drv2;
35750728Sphk		/* XXX: don't set bp->b_dev->si_disk (?) */
35850728Sphk	}
35950565Sphk	return (dssize(dev, &dp->d_slice));
36050565Sphk}
36151111Sjulian
36251111SjulianSYSCTL_DECL(_debug_sizeof);
36351111Sjulian
36451111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
36551111Sjulian    0, sizeof(struct disklabel), "sizeof(struct disklabel)");
36651111Sjulian
36751111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
36851111Sjulian    0, sizeof(struct diskslices), "sizeof(struct diskslices)");
36951111Sjulian
37051111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
37151111Sjulian    0, sizeof(struct disk), "sizeof(struct disk)");
372