subr_disk.c revision 92074
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 92074 2002-03-11 08:08:02Z phk $
1050565Sphk *
1150565Sphk */
1250565Sphk
1392074Sphk#include "opt_geom.h"
1492074Sphk#ifndef GEOM
1592074Sphk
1650565Sphk#include <sys/param.h>
1750565Sphk#include <sys/systm.h>
1850565Sphk#include <sys/kernel.h>
1951111Sjulian#include <sys/sysctl.h>
2060041Sphk#include <sys/bio.h>
2150565Sphk#include <sys/conf.h>
2250565Sphk#include <sys/disk.h>
2350565Sphk#include <sys/malloc.h>
2461953Snbm#include <sys/sysctl.h>
2550728Sphk#include <machine/md_var.h>
2664880Sphk#include <sys/ctype.h>
2764880Sphk
2869774Sphkstatic MALLOC_DEFINE(M_DISK, "disk", "disk data");
2950565Sphk
3050565Sphkstatic d_strategy_t diskstrategy;
3150565Sphkstatic d_open_t diskopen;
3250565Sphkstatic d_close_t diskclose;
3350565Sphkstatic d_ioctl_t diskioctl;
3450565Sphkstatic d_psize_t diskpsize;
3561717Sphk
3661717Sphkstatic LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist);
3764880Sphk
3885603Sphkvoid disk_dev_synth(dev_t dev);
3985603Sphk
4085603Sphkvoid
4185603Sphkdisk_dev_synth(dev_t dev)
4285603Sphk{
4385603Sphk	struct disk *dp;
4485603Sphk	int u, s, p;
4585603Sphk	dev_t pdev;
4685603Sphk
4786012Sphk	if (dksparebits(dev))
4885996Sphk		return;
4985603Sphk	LIST_FOREACH(dp, &disklist, d_list) {
5085603Sphk		if (major(dev) != dp->d_devsw->d_maj)
5185603Sphk			continue;
5285603Sphk		u = dkunit(dev);
5385603Sphk		p = RAW_PART;
5485603Sphk		s = WHOLE_DISK_SLICE;
5585603Sphk		pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p));
5685624Sphk		if (pdev->si_devsw == NULL)
5785624Sphk			return;		/* Probably a unit we don't have */
5885603Sphk		s = dkslice(dev);
5985603Sphk		p = dkpart(dev);
6085603Sphk		if (s == WHOLE_DISK_SLICE && p == RAW_PART) {
6185603Sphk			/* XXX: actually should not happen */
6285603Sphk			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
6385603Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%d",
6485603Sphk				dp->d_devsw->d_name, u);
6585603Sphk			dev_depends(pdev, dev);
6685603Sphk			return;
6785603Sphk		}
6885603Sphk		if (s == COMPATIBILITY_SLICE) {
6985603Sphk			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
7085603Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%d%c",
7185603Sphk				dp->d_devsw->d_name, u, 'a' + p);
7285603Sphk			dev_depends(pdev, dev);
7385603Sphk			return;
7485603Sphk		}
7585858Sphk		if (p != RAW_PART) {
7685858Sphk			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
7785858Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c",
7885858Sphk				dp->d_devsw->d_name, u, s - BASE_SLICE + 1,
7985858Sphk				'a' + p);
8085858Sphk		} else {
8185858Sphk			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
8285858Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d",
8385858Sphk				dp->d_devsw->d_name, u, s - BASE_SLICE + 1);
8485858Sphk			make_dev_alias(dev, "%s%ds%dc",
8585858Sphk			    dp->d_devsw->d_name, u, s - BASE_SLICE + 1);
8685858Sphk		}
8785603Sphk		dev_depends(pdev, dev);
8885603Sphk		return;
8985603Sphk	}
9085603Sphk}
9185603Sphk
9262617Simpstatic void
9364880Sphkdisk_clone(void *arg, char *name, int namelen, dev_t *dev)
9464880Sphk{
9564880Sphk	struct disk *dp;
9664880Sphk	char const *d;
9792074Sphk	char *e;
9892074Sphk	int j, u, s, p;
9964880Sphk	dev_t pdev;
10064880Sphk
10164880Sphk	if (*dev != NODEV)
10264880Sphk		return;
10364880Sphk
10464880Sphk	LIST_FOREACH(dp, &disklist, d_list) {
10564880Sphk		d = dp->d_devsw->d_name;
10692074Sphk		j = dev_stdclone(name, &e, d, &u);
10792074Sphk		if (j == 0)
10864880Sphk			continue;
10970058Sphk		if (u > DKMAXUNIT)
11070058Sphk			continue;
11164880Sphk		p = RAW_PART;
11264880Sphk		s = WHOLE_DISK_SLICE;
11364880Sphk		pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p));
11464880Sphk		if (pdev->si_disk == NULL)
11564880Sphk			continue;
11692074Sphk		if (*e != '\0') {
11792074Sphk			j = dev_stdclone(e, &e, "s", &s);
11892074Sphk			if (j == 0)
11992074Sphk				s = COMPATIBILITY_SLICE;
12092074Sphk			else if (j == 1 || j == 2)
12164880Sphk				s += BASE_SLICE - 1;
12292074Sphk			if (!*e)
12392074Sphk				;		/* ad0s1 case */
12492074Sphk			else if (e[1] != '\0')
12592074Sphk				return;		/* can never be a disk name */
12692074Sphk			else if (*e < 'a' || *e > 'h')
12792074Sphk				return;		/* can never be a disk name */
12864880Sphk			else
12992074Sphk				p = *e - 'a';
13064880Sphk		}
13192074Sphk		if (s == WHOLE_DISK_SLICE && p == RAW_PART) {
13292074Sphk			return;
13392074Sphk		} else if (s >= BASE_SLICE && p != RAW_PART) {
13485603Sphk			*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
13585603Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c",
13685858Sphk			    pdev->si_devsw->d_name, u, s - BASE_SLICE + 1,
13785858Sphk			    p + 'a');
13885858Sphk		} else if (s >= BASE_SLICE) {
13985603Sphk			*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
14085858Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d",
14185858Sphk			    pdev->si_devsw->d_name, u, s - BASE_SLICE + 1);
14285858Sphk			make_dev_alias(*dev, "%s%ds%dc",
14385858Sphk			    pdev->si_devsw->d_name, u, s - BASE_SLICE + 1);
14485858Sphk		} else {
14585858Sphk			*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
14692074Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%d%c",
14792074Sphk			    pdev->si_devsw->d_name, u, p + 'a');
14885858Sphk		}
14977215Sphk		dev_depends(pdev, *dev);
15064880Sphk		return;
15164880Sphk	}
15264880Sphk}
15364880Sphk
15464880Sphkstatic void
15562617Simpinherit_raw(dev_t pdev, dev_t dev)
15662617Simp{
15762617Simp	dev->si_disk = pdev->si_disk;
15862617Simp	dev->si_drv1 = pdev->si_drv1;
15962617Simp	dev->si_drv2 = pdev->si_drv2;
16062617Simp	dev->si_iosize_max = pdev->si_iosize_max;
16162617Simp	dev->si_bsize_phys = pdev->si_bsize_phys;
16262617Simp	dev->si_bsize_best = pdev->si_bsize_best;
16362617Simp}
16462617Simp
16550565Sphkdev_t
16651215Sphkdisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
16750565Sphk{
16864880Sphk	static int once;
16977408Sphk	dev_t dev;
17050565Sphk
17177215Sphk	if (!once) {
17277215Sphk		EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000);
17377215Sphk		once++;
17477215Sphk	}
17577215Sphk
17651198Sphk	bzero(dp, sizeof(*dp));
17751198Sphk
17877147Sphk	if (proto->d_open != diskopen) {
17951215Sphk		*proto = *cdevsw;
18051215Sphk		proto->d_open = diskopen;
18151215Sphk		proto->d_close = diskclose;
18251215Sphk		proto->d_ioctl = diskioctl;
18351215Sphk		proto->d_strategy = diskstrategy;
18451215Sphk		proto->d_psize = diskpsize;
18550565Sphk	}
18650565Sphk
18753437Sjkh	if (bootverbose)
18853437Sjkh		printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
18951243Sphk	dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
19064880Sphk	    UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit);
19150565Sphk
19250565Sphk	dev->si_disk = dp;
19350565Sphk	dp->d_dev = dev;
19452917Sphk	dp->d_dsflags = flags;
19551215Sphk	dp->d_devsw = cdevsw;
19661717Sphk	LIST_INSERT_HEAD(&disklist, dp, d_list);
19777215Sphk
19850565Sphk	return (dev);
19950565Sphk}
20050565Sphk
20150728Sphkint
20250728Sphkdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
20350728Sphk{
20450728Sphk	struct disk *dp;
20550728Sphk	struct disklabel *dl;
20650728Sphk	u_int boff;
20750728Sphk
20850728Sphk	dp = dev->si_disk;
20950728Sphk	if (!dp)
21050728Sphk		return (ENXIO);
21150728Sphk	if (!dp->d_slice)
21250728Sphk		return (ENXIO);
21350728Sphk	dl = dsgetlabel(dev, dp->d_slice);
21450728Sphk	if (!dl)
21550728Sphk		return (ENXIO);
21681688Sbde	*count = Maxmem * (PAGE_SIZE / dl->d_secsize);
21781688Sbde	if (dumplo <= LABELSECTOR ||
21850728Sphk	    (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
21950728Sphk		return (EINVAL);
22050728Sphk	boff = dl->d_partitions[dkpart(dev)].p_offset +
22150728Sphk	    dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
22250728Sphk	*blkno = boff + dumplo;
22350728Sphk	*secsize = dl->d_secsize;
22450728Sphk	return (0);
22550728Sphk
22650728Sphk}
22750728Sphk
22850728Sphkvoid
22950728Sphkdisk_invalidate (struct disk *disk)
23050728Sphk{
23157325Ssos	if (disk->d_slice)
23257325Ssos		dsgone(&disk->d_slice);
23350728Sphk}
23450728Sphk
23550565Sphkvoid
23656767Sphkdisk_destroy(dev_t dev)
23750565Sphk{
23861717Sphk	LIST_REMOVE(dev->si_disk, d_list);
23961717Sphk	bzero(dev->si_disk, sizeof(*dev->si_disk));
24057325Ssos    	dev->si_disk = NULL;
24157325Ssos	destroy_dev(dev);
24250565Sphk	return;
24350565Sphk}
24450565Sphk
24561717Sphkstruct disk *
24661717Sphkdisk_enumerate(struct disk *disk)
24761717Sphk{
24861717Sphk	if (!disk)
24961717Sphk		return (LIST_FIRST(&disklist));
25061717Sphk	else
25161717Sphk		return (LIST_NEXT(disk, d_list));
25261717Sphk}
25361717Sphk
25461953Snbmstatic int
25562573Sphksysctl_disks(SYSCTL_HANDLER_ARGS)
25661953Snbm{
25761953Snbm	struct disk *disk;
25861953Snbm	int error, first;
25961953Snbm
26061953Snbm	disk = NULL;
26161953Snbm	first = 1;
26261953Snbm
26361953Snbm	while ((disk = disk_enumerate(disk))) {
26461953Snbm		if (!first) {
26561953Snbm			error = SYSCTL_OUT(req, " ", 1);
26661953Snbm			if (error)
26761953Snbm				return error;
26861953Snbm		} else {
26961953Snbm			first = 0;
27061953Snbm		}
27161953Snbm		error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name));
27261953Snbm		if (error)
27361953Snbm			return error;
27461953Snbm	}
27561953Snbm	error = SYSCTL_OUT(req, "", 1);
27661953Snbm	return error;
27761953Snbm}
27861953Snbm
27961953SnbmSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL,
28061953Snbm    sysctl_disks, "A", "names of available disks");
28161953Snbm
28250728Sphk/*
28350728Sphk * The cdevsw functions
28450728Sphk */
28550728Sphk
28650565Sphkstatic int
28783366Sjuliandiskopen(dev_t dev, int oflags, int devtype, struct thread *td)
28850565Sphk{
28950565Sphk	dev_t pdev;
29050565Sphk	struct disk *dp;
29150565Sphk	int error;
29250565Sphk
29350728Sphk	error = 0;
29450565Sphk	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
29550728Sphk
29650565Sphk	dp = pdev->si_disk;
29750565Sphk	if (!dp)
29850565Sphk		return (ENXIO);
29950728Sphk
30052917Sphk	while (dp->d_flags & DISKFLAG_LOCK) {
30152917Sphk		dp->d_flags |= DISKFLAG_WANTED;
30254815Sphk		error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
30354815Sphk		if (error)
30454815Sphk			return (error);
30552917Sphk	}
30652917Sphk	dp->d_flags |= DISKFLAG_LOCK;
30752917Sphk
30851860Sphk	if (!dsisopen(dp->d_slice)) {
30951878Ssos		if (!pdev->si_iosize_max)
31051878Ssos			pdev->si_iosize_max = dev->si_iosize_max;
31183366Sjulian		error = dp->d_devsw->d_open(pdev, oflags, devtype, td);
31251860Sphk	}
31351826Sphk
31451826Sphk	/* Inherit properties from the whole/raw dev_t */
31562617Simp	inherit_raw(pdev, dev);
31650728Sphk
31750728Sphk	if (error)
31852917Sphk		goto out;
31950728Sphk
32052917Sphk	error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
32150565Sphk
32250728Sphk	if (!dsisopen(dp->d_slice))
32383366Sjulian		dp->d_devsw->d_close(pdev, oflags, devtype, td);
32452917Sphkout:
32552917Sphk	dp->d_flags &= ~DISKFLAG_LOCK;
32652917Sphk	if (dp->d_flags & DISKFLAG_WANTED) {
32752917Sphk		dp->d_flags &= ~DISKFLAG_WANTED;
32852917Sphk		wakeup(dp);
32952917Sphk	}
33050728Sphk
33150565Sphk	return(error);
33250565Sphk}
33350565Sphk
33450565Sphkstatic int
33583366Sjuliandiskclose(dev_t dev, int fflag, int devtype, struct thread *td)
33650565Sphk{
33750565Sphk	struct disk *dp;
33850565Sphk	int error;
33962617Simp	dev_t pdev;
34050565Sphk
34150565Sphk	error = 0;
34262617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
34362617Simp	dp = pdev->si_disk;
34474206Ssos	if (!dp)
34574206Ssos		return (ENXIO);
34651822Sphk	dsclose(dev, devtype, dp->d_slice);
34774206Ssos	if (!dsisopen(dp->d_slice))
34883366Sjulian		error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td);
34950565Sphk	return (error);
35050565Sphk}
35150565Sphk
35250565Sphkstatic void
35359249Sphkdiskstrategy(struct bio *bp)
35450565Sphk{
35550565Sphk	dev_t pdev;
35650565Sphk	struct disk *dp;
35750565Sphk
35862617Simp	pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
35962617Simp	dp = pdev->si_disk;
36076361Sphk	bp->bio_resid = bp->bio_bcount;
36162617Simp	if (dp != bp->bio_dev->si_disk)
36262617Simp		inherit_raw(pdev, bp->bio_dev);
36350565Sphk
36450565Sphk	if (!dp) {
36576322Sphk		biofinish(bp, NULL, ENXIO);
36650565Sphk		return;
36750565Sphk	}
36850565Sphk
36955763Sphk	if (dscheck(bp, dp->d_slice) <= 0) {
37050565Sphk		biodone(bp);
37150565Sphk		return;
37250565Sphk	}
37350565Sphk
37476324Sphk	if (bp->bio_bcount == 0) {
37576324Sphk		biodone(bp);
37676324Sphk		return;
37776324Sphk	}
37876324Sphk
37959623Sphk	KASSERT(dp->d_devsw != NULL, ("NULL devsw"));
38059623Sphk	KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy"));
38151215Sphk	dp->d_devsw->d_strategy(bp);
38250565Sphk	return;
38350565Sphk
38450565Sphk}
38550565Sphk
38650565Sphkstatic int
38783366Sjuliandiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
38850565Sphk{
38950565Sphk	struct disk *dp;
39050565Sphk	int error;
39162617Simp	dev_t pdev;
39250565Sphk
39362617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
39462617Simp	dp = pdev->si_disk;
39574206Ssos	if (!dp)
39674206Ssos		return (ENXIO);
39750565Sphk	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
39850565Sphk	if (error == ENOIOCTL)
39983366Sjulian		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td);
40050565Sphk	return (error);
40150565Sphk}
40250565Sphk
40350565Sphkstatic int
40450565Sphkdiskpsize(dev_t dev)
40550565Sphk{
40650565Sphk	struct disk *dp;
40750728Sphk	dev_t pdev;
40850565Sphk
40962617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
41062617Simp	dp = pdev->si_disk;
41162617Simp	if (!dp)
41262617Simp		return (-1);
41362617Simp	if (dp != dev->si_disk) {
41450728Sphk		dev->si_drv1 = pdev->si_drv1;
41550728Sphk		dev->si_drv2 = pdev->si_drv2;
41650728Sphk		/* XXX: don't set bp->b_dev->si_disk (?) */
41750728Sphk	}
41850565Sphk	return (dssize(dev, &dp->d_slice));
41950565Sphk}
42051111Sjulian
42151111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
42251111Sjulian    0, sizeof(struct disklabel), "sizeof(struct disklabel)");
42351111Sjulian
42451111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
42551111Sjulian    0, sizeof(struct diskslices), "sizeof(struct diskslices)");
42651111Sjulian
42751111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
42851111Sjulian    0, sizeof(struct disk), "sizeof(struct disk)");
42992074Sphk
43092074Sphk#endif
431