subr_disk.c revision 85603
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 85603 2001-10-27 17:44:21Z 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
3585603Sphkvoid disk_dev_synth(dev_t dev);
3685603Sphk
3785603Sphkvoid
3885603Sphkdisk_dev_synth(dev_t dev)
3985603Sphk{
4085603Sphk	struct disk *dp;
4185603Sphk	int u, s, p;
4285603Sphk	dev_t pdev;
4385603Sphk
4485603Sphk	LIST_FOREACH(dp, &disklist, d_list) {
4585603Sphk		if (major(dev) != dp->d_devsw->d_maj)
4685603Sphk			continue;
4785603Sphk		u = dkunit(dev);
4885603Sphk		p = RAW_PART;
4985603Sphk		s = WHOLE_DISK_SLICE;
5085603Sphk		pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p));
5185603Sphk		s = dkslice(dev);
5285603Sphk		p = dkpart(dev);
5385603Sphk		if (s == WHOLE_DISK_SLICE && p == RAW_PART) {
5485603Sphk			/* XXX: actually should not happen */
5585603Sphk			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
5685603Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%d",
5785603Sphk				dp->d_devsw->d_name, u);
5885603Sphk			dev_depends(pdev, dev);
5985603Sphk			return;
6085603Sphk		}
6185603Sphk		if (s == COMPATIBILITY_SLICE) {
6285603Sphk			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
6385603Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%d%c",
6485603Sphk				dp->d_devsw->d_name, u, 'a' + p);
6585603Sphk			dev_depends(pdev, dev);
6685603Sphk			return;
6785603Sphk		}
6885603Sphk		dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
6985603Sphk		    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c",
7085603Sphk			dp->d_devsw->d_name, u, s - BASE_SLICE + 1, 'a' + p);
7185603Sphk		dev_depends(pdev, dev);
7285603Sphk		if (p == RAW_PART)
7385603Sphk			make_dev_alias(dev, "%s%ds%d",
7485603Sphk			    dp->d_devsw->d_name, u, s - BASE_SLICE + 1);
7585603Sphk		return;
7685603Sphk	}
7785603Sphk}
7885603Sphk
7962617Simpstatic void
8064880Sphkdisk_clone(void *arg, char *name, int namelen, dev_t *dev)
8164880Sphk{
8264880Sphk	struct disk *dp;
8364880Sphk	char const *d;
8464880Sphk	int i, u, s, p;
8564880Sphk	dev_t pdev;
8664880Sphk
8764880Sphk	if (*dev != NODEV)
8864880Sphk		return;
8964880Sphk
9064880Sphk	LIST_FOREACH(dp, &disklist, d_list) {
9164880Sphk		d = dp->d_devsw->d_name;
9264880Sphk		i = strlen(d);
9364880Sphk		if (bcmp(d, name, i) != 0)
9464880Sphk			continue;
9564880Sphk		u = 0;
9664880Sphk		if (!isdigit(name[i]))
9764880Sphk			continue;
9864880Sphk		while (isdigit(name[i])) {
9964880Sphk			u *= 10;
10064880Sphk			u += name[i++] - '0';
10164880Sphk		}
10270058Sphk		if (u > DKMAXUNIT)
10370058Sphk			continue;
10464880Sphk		p = RAW_PART;
10564880Sphk		s = WHOLE_DISK_SLICE;
10664880Sphk		pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p));
10764880Sphk		if (pdev->si_disk == NULL)
10864880Sphk			continue;
10964880Sphk		if (name[i] != '\0') {
11064880Sphk			if (name[i] == 's') {
11164880Sphk				s = 0;
11264880Sphk				i++;
11364880Sphk				if (!isdigit(name[i]))
11464880Sphk					continue;
11564880Sphk				while (isdigit(name[i])) {
11664880Sphk					s *= 10;
11764880Sphk					s += name[i++] - '0';
11864880Sphk				}
11964880Sphk				s += BASE_SLICE - 1;
12064880Sphk			} else {
12164880Sphk				s = COMPATIBILITY_SLICE;
12264880Sphk			}
12364880Sphk			if (name[i] == '\0')
12464880Sphk				;
12585311Sphk			else if (name[i + 1] != '\0')
12685311Sphk				return;
12764880Sphk			else if (name[i] < 'a' || name[i] > 'h')
12864880Sphk				continue;
12964880Sphk			else
13064880Sphk				p = name[i] - 'a';
13164880Sphk		}
13264880Sphk
13385603Sphk		if (s >= BASE_SLICE)
13485603Sphk			*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
13585603Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c",
13685603Sphk			    pdev->si_devsw->d_name, u, s - BASE_SLICE + 1, p + 'a');
13785603Sphk		else
13885603Sphk			*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
13985603Sphk			    UID_ROOT, GID_OPERATOR, 0640, name);
14077215Sphk		dev_depends(pdev, *dev);
14185603Sphk		if (s >= BASE_SLICE && p == RAW_PART) {
14285603Sphk			make_dev_alias(*dev, "%s%ds%d",
14385603Sphk			    pdev->si_devsw->d_name, u, s - BASE_SLICE + 1);
14485603Sphk		}
14564880Sphk		return;
14664880Sphk	}
14764880Sphk}
14864880Sphk
14964880Sphkstatic void
15062617Simpinherit_raw(dev_t pdev, dev_t dev)
15162617Simp{
15262617Simp	dev->si_disk = pdev->si_disk;
15362617Simp	dev->si_drv1 = pdev->si_drv1;
15462617Simp	dev->si_drv2 = pdev->si_drv2;
15562617Simp	dev->si_iosize_max = pdev->si_iosize_max;
15662617Simp	dev->si_bsize_phys = pdev->si_bsize_phys;
15762617Simp	dev->si_bsize_best = pdev->si_bsize_best;
15862617Simp}
15962617Simp
16050565Sphkdev_t
16151215Sphkdisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
16250565Sphk{
16364880Sphk	static int once;
16477408Sphk	dev_t dev;
16550565Sphk
16677215Sphk	if (!once) {
16777215Sphk		EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000);
16877215Sphk		once++;
16977215Sphk	}
17077215Sphk
17151198Sphk	bzero(dp, sizeof(*dp));
17251198Sphk
17377147Sphk	if (proto->d_open != diskopen) {
17451215Sphk		*proto = *cdevsw;
17551215Sphk		proto->d_open = diskopen;
17651215Sphk		proto->d_close = diskclose;
17751215Sphk		proto->d_ioctl = diskioctl;
17851215Sphk		proto->d_strategy = diskstrategy;
17951215Sphk		proto->d_psize = diskpsize;
18077343Sphk		cdevsw_add(proto);
18150565Sphk	}
18250565Sphk
18353437Sjkh	if (bootverbose)
18453437Sjkh		printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
18551243Sphk	dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
18664880Sphk	    UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit);
18750565Sphk
18850565Sphk	dev->si_disk = dp;
18950565Sphk	dp->d_dev = dev;
19052917Sphk	dp->d_dsflags = flags;
19151215Sphk	dp->d_devsw = cdevsw;
19261717Sphk	LIST_INSERT_HEAD(&disklist, dp, d_list);
19377215Sphk
19450565Sphk	return (dev);
19550565Sphk}
19650565Sphk
19750728Sphkint
19850728Sphkdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
19950728Sphk{
20050728Sphk	struct disk *dp;
20150728Sphk	struct disklabel *dl;
20250728Sphk	u_int boff;
20350728Sphk
20450728Sphk	dp = dev->si_disk;
20550728Sphk	if (!dp)
20650728Sphk		return (ENXIO);
20750728Sphk	if (!dp->d_slice)
20850728Sphk		return (ENXIO);
20950728Sphk	dl = dsgetlabel(dev, dp->d_slice);
21050728Sphk	if (!dl)
21150728Sphk		return (ENXIO);
21281688Sbde	*count = Maxmem * (PAGE_SIZE / dl->d_secsize);
21381688Sbde	if (dumplo <= LABELSECTOR ||
21450728Sphk	    (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
21550728Sphk		return (EINVAL);
21650728Sphk	boff = dl->d_partitions[dkpart(dev)].p_offset +
21750728Sphk	    dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
21850728Sphk	*blkno = boff + dumplo;
21950728Sphk	*secsize = dl->d_secsize;
22050728Sphk	return (0);
22150728Sphk
22250728Sphk}
22350728Sphk
22450728Sphkvoid
22550728Sphkdisk_invalidate (struct disk *disk)
22650728Sphk{
22757325Ssos	if (disk->d_slice)
22857325Ssos		dsgone(&disk->d_slice);
22950728Sphk}
23050728Sphk
23150565Sphkvoid
23256767Sphkdisk_destroy(dev_t dev)
23350565Sphk{
23461717Sphk	LIST_REMOVE(dev->si_disk, d_list);
23561717Sphk	bzero(dev->si_disk, sizeof(*dev->si_disk));
23657325Ssos    	dev->si_disk = NULL;
23757325Ssos	destroy_dev(dev);
23850565Sphk	return;
23950565Sphk}
24050565Sphk
24161717Sphkstruct disk *
24261717Sphkdisk_enumerate(struct disk *disk)
24361717Sphk{
24461717Sphk	if (!disk)
24561717Sphk		return (LIST_FIRST(&disklist));
24661717Sphk	else
24761717Sphk		return (LIST_NEXT(disk, d_list));
24861717Sphk}
24961717Sphk
25061953Snbmstatic int
25162573Sphksysctl_disks(SYSCTL_HANDLER_ARGS)
25261953Snbm{
25361953Snbm	struct disk *disk;
25461953Snbm	int error, first;
25561953Snbm
25661953Snbm	disk = NULL;
25761953Snbm	first = 1;
25861953Snbm
25961953Snbm	while ((disk = disk_enumerate(disk))) {
26061953Snbm		if (!first) {
26161953Snbm			error = SYSCTL_OUT(req, " ", 1);
26261953Snbm			if (error)
26361953Snbm				return error;
26461953Snbm		} else {
26561953Snbm			first = 0;
26661953Snbm		}
26761953Snbm		error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name));
26861953Snbm		if (error)
26961953Snbm			return error;
27061953Snbm	}
27161953Snbm	error = SYSCTL_OUT(req, "", 1);
27261953Snbm	return error;
27361953Snbm}
27461953Snbm
27561953SnbmSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL,
27661953Snbm    sysctl_disks, "A", "names of available disks");
27761953Snbm
27850728Sphk/*
27950728Sphk * The cdevsw functions
28050728Sphk */
28150728Sphk
28250565Sphkstatic int
28383366Sjuliandiskopen(dev_t dev, int oflags, int devtype, struct thread *td)
28450565Sphk{
28550565Sphk	dev_t pdev;
28650565Sphk	struct disk *dp;
28750565Sphk	int error;
28850565Sphk
28950728Sphk	error = 0;
29050565Sphk	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
29150728Sphk
29250565Sphk	dp = pdev->si_disk;
29350565Sphk	if (!dp)
29450565Sphk		return (ENXIO);
29550728Sphk
29652917Sphk	while (dp->d_flags & DISKFLAG_LOCK) {
29752917Sphk		dp->d_flags |= DISKFLAG_WANTED;
29854815Sphk		error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
29954815Sphk		if (error)
30054815Sphk			return (error);
30152917Sphk	}
30252917Sphk	dp->d_flags |= DISKFLAG_LOCK;
30352917Sphk
30451860Sphk	if (!dsisopen(dp->d_slice)) {
30551878Ssos		if (!pdev->si_iosize_max)
30651878Ssos			pdev->si_iosize_max = dev->si_iosize_max;
30783366Sjulian		error = dp->d_devsw->d_open(pdev, oflags, devtype, td);
30851860Sphk	}
30951826Sphk
31051826Sphk	/* Inherit properties from the whole/raw dev_t */
31162617Simp	inherit_raw(pdev, dev);
31250728Sphk
31350728Sphk	if (error)
31452917Sphk		goto out;
31550728Sphk
31652917Sphk	error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
31750565Sphk
31850728Sphk	if (!dsisopen(dp->d_slice))
31983366Sjulian		dp->d_devsw->d_close(pdev, oflags, devtype, td);
32052917Sphkout:
32152917Sphk	dp->d_flags &= ~DISKFLAG_LOCK;
32252917Sphk	if (dp->d_flags & DISKFLAG_WANTED) {
32352917Sphk		dp->d_flags &= ~DISKFLAG_WANTED;
32452917Sphk		wakeup(dp);
32552917Sphk	}
32650728Sphk
32750565Sphk	return(error);
32850565Sphk}
32950565Sphk
33050565Sphkstatic int
33183366Sjuliandiskclose(dev_t dev, int fflag, int devtype, struct thread *td)
33250565Sphk{
33350565Sphk	struct disk *dp;
33450565Sphk	int error;
33562617Simp	dev_t pdev;
33650565Sphk
33750565Sphk	error = 0;
33862617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
33962617Simp	dp = pdev->si_disk;
34074206Ssos	if (!dp)
34174206Ssos		return (ENXIO);
34251822Sphk	dsclose(dev, devtype, dp->d_slice);
34374206Ssos	if (!dsisopen(dp->d_slice))
34483366Sjulian		error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td);
34550565Sphk	return (error);
34650565Sphk}
34750565Sphk
34850565Sphkstatic void
34959249Sphkdiskstrategy(struct bio *bp)
35050565Sphk{
35150565Sphk	dev_t pdev;
35250565Sphk	struct disk *dp;
35350565Sphk
35462617Simp	pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
35562617Simp	dp = pdev->si_disk;
35676361Sphk	bp->bio_resid = bp->bio_bcount;
35762617Simp	if (dp != bp->bio_dev->si_disk)
35862617Simp		inherit_raw(pdev, bp->bio_dev);
35950565Sphk
36050565Sphk	if (!dp) {
36176322Sphk		biofinish(bp, NULL, ENXIO);
36250565Sphk		return;
36350565Sphk	}
36450565Sphk
36555763Sphk	if (dscheck(bp, dp->d_slice) <= 0) {
36650565Sphk		biodone(bp);
36750565Sphk		return;
36850565Sphk	}
36950565Sphk
37076324Sphk	if (bp->bio_bcount == 0) {
37176324Sphk		biodone(bp);
37276324Sphk		return;
37376324Sphk	}
37476324Sphk
37559623Sphk	KASSERT(dp->d_devsw != NULL, ("NULL devsw"));
37659623Sphk	KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy"));
37751215Sphk	dp->d_devsw->d_strategy(bp);
37850565Sphk	return;
37950565Sphk
38050565Sphk}
38150565Sphk
38250565Sphkstatic int
38383366Sjuliandiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
38450565Sphk{
38550565Sphk	struct disk *dp;
38650565Sphk	int error;
38762617Simp	dev_t pdev;
38850565Sphk
38962617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
39062617Simp	dp = pdev->si_disk;
39174206Ssos	if (!dp)
39274206Ssos		return (ENXIO);
39350565Sphk	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
39450565Sphk	if (error == ENOIOCTL)
39583366Sjulian		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td);
39650565Sphk	return (error);
39750565Sphk}
39850565Sphk
39950565Sphkstatic int
40050565Sphkdiskpsize(dev_t dev)
40150565Sphk{
40250565Sphk	struct disk *dp;
40350728Sphk	dev_t pdev;
40450565Sphk
40562617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
40662617Simp	dp = pdev->si_disk;
40762617Simp	if (!dp)
40862617Simp		return (-1);
40962617Simp	if (dp != dev->si_disk) {
41050728Sphk		dev->si_drv1 = pdev->si_drv1;
41150728Sphk		dev->si_drv2 = pdev->si_drv2;
41250728Sphk		/* XXX: don't set bp->b_dev->si_disk (?) */
41350728Sphk	}
41450565Sphk	return (dssize(dev, &dp->d_slice));
41550565Sphk}
41651111Sjulian
41751111SjulianSYSCTL_DECL(_debug_sizeof);
41851111Sjulian
41951111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
42051111Sjulian    0, sizeof(struct disklabel), "sizeof(struct disklabel)");
42151111Sjulian
42251111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
42351111Sjulian    0, sizeof(struct diskslices), "sizeof(struct diskslices)");
42451111Sjulian
42551111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
42651111Sjulian    0, sizeof(struct disk), "sizeof(struct disk)");
427