subr_disk.c revision 85996
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 85996 2001-11-03 23:21:00Z 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
4485996Sphk	if (dktype(dev))
4585996Sphk		return;
4685603Sphk	LIST_FOREACH(dp, &disklist, d_list) {
4785603Sphk		if (major(dev) != dp->d_devsw->d_maj)
4885603Sphk			continue;
4985603Sphk		u = dkunit(dev);
5085603Sphk		p = RAW_PART;
5185603Sphk		s = WHOLE_DISK_SLICE;
5285603Sphk		pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p));
5385624Sphk		if (pdev->si_devsw == NULL)
5485624Sphk			return;		/* Probably a unit we don't have */
5585603Sphk		s = dkslice(dev);
5685603Sphk		p = dkpart(dev);
5785603Sphk		if (s == WHOLE_DISK_SLICE && p == RAW_PART) {
5885603Sphk			/* XXX: actually should not happen */
5985603Sphk			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
6085603Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%d",
6185603Sphk				dp->d_devsw->d_name, u);
6285603Sphk			dev_depends(pdev, dev);
6385603Sphk			return;
6485603Sphk		}
6585603Sphk		if (s == COMPATIBILITY_SLICE) {
6685603Sphk			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
6785603Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%d%c",
6885603Sphk				dp->d_devsw->d_name, u, 'a' + p);
6985603Sphk			dev_depends(pdev, dev);
7085603Sphk			return;
7185603Sphk		}
7285858Sphk		if (p != RAW_PART) {
7385858Sphk			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
7485858Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c",
7585858Sphk				dp->d_devsw->d_name, u, s - BASE_SLICE + 1,
7685858Sphk				'a' + p);
7785858Sphk		} else {
7885858Sphk			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
7985858Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d",
8085858Sphk				dp->d_devsw->d_name, u, s - BASE_SLICE + 1);
8185858Sphk			make_dev_alias(dev, "%s%ds%dc",
8285858Sphk			    dp->d_devsw->d_name, u, s - BASE_SLICE + 1);
8385858Sphk		}
8485603Sphk		dev_depends(pdev, dev);
8585603Sphk		return;
8685603Sphk	}
8785603Sphk}
8885603Sphk
8962617Simpstatic void
9064880Sphkdisk_clone(void *arg, char *name, int namelen, dev_t *dev)
9164880Sphk{
9264880Sphk	struct disk *dp;
9364880Sphk	char const *d;
9464880Sphk	int i, u, s, p;
9564880Sphk	dev_t pdev;
9664880Sphk
9764880Sphk	if (*dev != NODEV)
9864880Sphk		return;
9964880Sphk
10064880Sphk	LIST_FOREACH(dp, &disklist, d_list) {
10164880Sphk		d = dp->d_devsw->d_name;
10264880Sphk		i = strlen(d);
10364880Sphk		if (bcmp(d, name, i) != 0)
10464880Sphk			continue;
10564880Sphk		u = 0;
10664880Sphk		if (!isdigit(name[i]))
10764880Sphk			continue;
10864880Sphk		while (isdigit(name[i])) {
10964880Sphk			u *= 10;
11064880Sphk			u += name[i++] - '0';
11164880Sphk		}
11270058Sphk		if (u > DKMAXUNIT)
11370058Sphk			continue;
11464880Sphk		p = RAW_PART;
11564880Sphk		s = WHOLE_DISK_SLICE;
11664880Sphk		pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p));
11764880Sphk		if (pdev->si_disk == NULL)
11864880Sphk			continue;
11964880Sphk		if (name[i] != '\0') {
12064880Sphk			if (name[i] == 's') {
12164880Sphk				s = 0;
12264880Sphk				i++;
12364880Sphk				if (!isdigit(name[i]))
12464880Sphk					continue;
12564880Sphk				while (isdigit(name[i])) {
12664880Sphk					s *= 10;
12764880Sphk					s += name[i++] - '0';
12864880Sphk				}
12964880Sphk				s += BASE_SLICE - 1;
13064880Sphk			} else {
13164880Sphk				s = COMPATIBILITY_SLICE;
13264880Sphk			}
13364880Sphk			if (name[i] == '\0')
13464880Sphk				;
13585311Sphk			else if (name[i + 1] != '\0')
13685311Sphk				return;
13764880Sphk			else if (name[i] < 'a' || name[i] > 'h')
13864880Sphk				continue;
13964880Sphk			else
14064880Sphk				p = name[i] - 'a';
14164880Sphk		}
14264880Sphk
14385858Sphk		if (s >= BASE_SLICE && p != RAW_PART) {
14485603Sphk			*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
14585603Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c",
14685858Sphk			    pdev->si_devsw->d_name, u, s - BASE_SLICE + 1,
14785858Sphk			    p + 'a');
14885858Sphk		} else if (s >= BASE_SLICE) {
14985603Sphk			*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
15085858Sphk			    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d",
15185858Sphk			    pdev->si_devsw->d_name, u, s - BASE_SLICE + 1);
15285858Sphk			make_dev_alias(*dev, "%s%ds%dc",
15385858Sphk			    pdev->si_devsw->d_name, u, s - BASE_SLICE + 1);
15485858Sphk		} else {
15585858Sphk			*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
15685603Sphk			    UID_ROOT, GID_OPERATOR, 0640, name);
15785858Sphk		}
15877215Sphk		dev_depends(pdev, *dev);
15964880Sphk		return;
16064880Sphk	}
16164880Sphk}
16264880Sphk
16364880Sphkstatic void
16462617Simpinherit_raw(dev_t pdev, dev_t dev)
16562617Simp{
16662617Simp	dev->si_disk = pdev->si_disk;
16762617Simp	dev->si_drv1 = pdev->si_drv1;
16862617Simp	dev->si_drv2 = pdev->si_drv2;
16962617Simp	dev->si_iosize_max = pdev->si_iosize_max;
17062617Simp	dev->si_bsize_phys = pdev->si_bsize_phys;
17162617Simp	dev->si_bsize_best = pdev->si_bsize_best;
17262617Simp}
17362617Simp
17450565Sphkdev_t
17551215Sphkdisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
17650565Sphk{
17764880Sphk	static int once;
17877408Sphk	dev_t dev;
17950565Sphk
18077215Sphk	if (!once) {
18177215Sphk		EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000);
18277215Sphk		once++;
18377215Sphk	}
18477215Sphk
18551198Sphk	bzero(dp, sizeof(*dp));
18651198Sphk
18777147Sphk	if (proto->d_open != diskopen) {
18851215Sphk		*proto = *cdevsw;
18951215Sphk		proto->d_open = diskopen;
19051215Sphk		proto->d_close = diskclose;
19151215Sphk		proto->d_ioctl = diskioctl;
19251215Sphk		proto->d_strategy = diskstrategy;
19351215Sphk		proto->d_psize = diskpsize;
19477343Sphk		cdevsw_add(proto);
19550565Sphk	}
19650565Sphk
19753437Sjkh	if (bootverbose)
19853437Sjkh		printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
19951243Sphk	dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
20064880Sphk	    UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit);
20150565Sphk
20250565Sphk	dev->si_disk = dp;
20350565Sphk	dp->d_dev = dev;
20452917Sphk	dp->d_dsflags = flags;
20551215Sphk	dp->d_devsw = cdevsw;
20661717Sphk	LIST_INSERT_HEAD(&disklist, dp, d_list);
20777215Sphk
20850565Sphk	return (dev);
20950565Sphk}
21050565Sphk
21150728Sphkint
21250728Sphkdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
21350728Sphk{
21450728Sphk	struct disk *dp;
21550728Sphk	struct disklabel *dl;
21650728Sphk	u_int boff;
21750728Sphk
21850728Sphk	dp = dev->si_disk;
21950728Sphk	if (!dp)
22050728Sphk		return (ENXIO);
22150728Sphk	if (!dp->d_slice)
22250728Sphk		return (ENXIO);
22350728Sphk	dl = dsgetlabel(dev, dp->d_slice);
22450728Sphk	if (!dl)
22550728Sphk		return (ENXIO);
22681688Sbde	*count = Maxmem * (PAGE_SIZE / dl->d_secsize);
22781688Sbde	if (dumplo <= LABELSECTOR ||
22850728Sphk	    (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
22950728Sphk		return (EINVAL);
23050728Sphk	boff = dl->d_partitions[dkpart(dev)].p_offset +
23150728Sphk	    dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
23250728Sphk	*blkno = boff + dumplo;
23350728Sphk	*secsize = dl->d_secsize;
23450728Sphk	return (0);
23550728Sphk
23650728Sphk}
23750728Sphk
23850728Sphkvoid
23950728Sphkdisk_invalidate (struct disk *disk)
24050728Sphk{
24157325Ssos	if (disk->d_slice)
24257325Ssos		dsgone(&disk->d_slice);
24350728Sphk}
24450728Sphk
24550565Sphkvoid
24656767Sphkdisk_destroy(dev_t dev)
24750565Sphk{
24861717Sphk	LIST_REMOVE(dev->si_disk, d_list);
24961717Sphk	bzero(dev->si_disk, sizeof(*dev->si_disk));
25057325Ssos    	dev->si_disk = NULL;
25157325Ssos	destroy_dev(dev);
25250565Sphk	return;
25350565Sphk}
25450565Sphk
25561717Sphkstruct disk *
25661717Sphkdisk_enumerate(struct disk *disk)
25761717Sphk{
25861717Sphk	if (!disk)
25961717Sphk		return (LIST_FIRST(&disklist));
26061717Sphk	else
26161717Sphk		return (LIST_NEXT(disk, d_list));
26261717Sphk}
26361717Sphk
26461953Snbmstatic int
26562573Sphksysctl_disks(SYSCTL_HANDLER_ARGS)
26661953Snbm{
26761953Snbm	struct disk *disk;
26861953Snbm	int error, first;
26961953Snbm
27061953Snbm	disk = NULL;
27161953Snbm	first = 1;
27261953Snbm
27361953Snbm	while ((disk = disk_enumerate(disk))) {
27461953Snbm		if (!first) {
27561953Snbm			error = SYSCTL_OUT(req, " ", 1);
27661953Snbm			if (error)
27761953Snbm				return error;
27861953Snbm		} else {
27961953Snbm			first = 0;
28061953Snbm		}
28161953Snbm		error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name));
28261953Snbm		if (error)
28361953Snbm			return error;
28461953Snbm	}
28561953Snbm	error = SYSCTL_OUT(req, "", 1);
28661953Snbm	return error;
28761953Snbm}
28861953Snbm
28961953SnbmSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL,
29061953Snbm    sysctl_disks, "A", "names of available disks");
29161953Snbm
29250728Sphk/*
29350728Sphk * The cdevsw functions
29450728Sphk */
29550728Sphk
29650565Sphkstatic int
29783366Sjuliandiskopen(dev_t dev, int oflags, int devtype, struct thread *td)
29850565Sphk{
29950565Sphk	dev_t pdev;
30050565Sphk	struct disk *dp;
30150565Sphk	int error;
30250565Sphk
30350728Sphk	error = 0;
30450565Sphk	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
30550728Sphk
30650565Sphk	dp = pdev->si_disk;
30750565Sphk	if (!dp)
30850565Sphk		return (ENXIO);
30950728Sphk
31052917Sphk	while (dp->d_flags & DISKFLAG_LOCK) {
31152917Sphk		dp->d_flags |= DISKFLAG_WANTED;
31254815Sphk		error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
31354815Sphk		if (error)
31454815Sphk			return (error);
31552917Sphk	}
31652917Sphk	dp->d_flags |= DISKFLAG_LOCK;
31752917Sphk
31851860Sphk	if (!dsisopen(dp->d_slice)) {
31951878Ssos		if (!pdev->si_iosize_max)
32051878Ssos			pdev->si_iosize_max = dev->si_iosize_max;
32183366Sjulian		error = dp->d_devsw->d_open(pdev, oflags, devtype, td);
32251860Sphk	}
32351826Sphk
32451826Sphk	/* Inherit properties from the whole/raw dev_t */
32562617Simp	inherit_raw(pdev, dev);
32650728Sphk
32750728Sphk	if (error)
32852917Sphk		goto out;
32950728Sphk
33052917Sphk	error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
33150565Sphk
33250728Sphk	if (!dsisopen(dp->d_slice))
33383366Sjulian		dp->d_devsw->d_close(pdev, oflags, devtype, td);
33452917Sphkout:
33552917Sphk	dp->d_flags &= ~DISKFLAG_LOCK;
33652917Sphk	if (dp->d_flags & DISKFLAG_WANTED) {
33752917Sphk		dp->d_flags &= ~DISKFLAG_WANTED;
33852917Sphk		wakeup(dp);
33952917Sphk	}
34050728Sphk
34150565Sphk	return(error);
34250565Sphk}
34350565Sphk
34450565Sphkstatic int
34583366Sjuliandiskclose(dev_t dev, int fflag, int devtype, struct thread *td)
34650565Sphk{
34750565Sphk	struct disk *dp;
34850565Sphk	int error;
34962617Simp	dev_t pdev;
35050565Sphk
35150565Sphk	error = 0;
35262617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
35362617Simp	dp = pdev->si_disk;
35474206Ssos	if (!dp)
35574206Ssos		return (ENXIO);
35651822Sphk	dsclose(dev, devtype, dp->d_slice);
35774206Ssos	if (!dsisopen(dp->d_slice))
35883366Sjulian		error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td);
35950565Sphk	return (error);
36050565Sphk}
36150565Sphk
36250565Sphkstatic void
36359249Sphkdiskstrategy(struct bio *bp)
36450565Sphk{
36550565Sphk	dev_t pdev;
36650565Sphk	struct disk *dp;
36750565Sphk
36862617Simp	pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
36962617Simp	dp = pdev->si_disk;
37076361Sphk	bp->bio_resid = bp->bio_bcount;
37162617Simp	if (dp != bp->bio_dev->si_disk)
37262617Simp		inherit_raw(pdev, bp->bio_dev);
37350565Sphk
37450565Sphk	if (!dp) {
37576322Sphk		biofinish(bp, NULL, ENXIO);
37650565Sphk		return;
37750565Sphk	}
37850565Sphk
37955763Sphk	if (dscheck(bp, dp->d_slice) <= 0) {
38050565Sphk		biodone(bp);
38150565Sphk		return;
38250565Sphk	}
38350565Sphk
38476324Sphk	if (bp->bio_bcount == 0) {
38576324Sphk		biodone(bp);
38676324Sphk		return;
38776324Sphk	}
38876324Sphk
38959623Sphk	KASSERT(dp->d_devsw != NULL, ("NULL devsw"));
39059623Sphk	KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy"));
39151215Sphk	dp->d_devsw->d_strategy(bp);
39250565Sphk	return;
39350565Sphk
39450565Sphk}
39550565Sphk
39650565Sphkstatic int
39783366Sjuliandiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
39850565Sphk{
39950565Sphk	struct disk *dp;
40050565Sphk	int error;
40162617Simp	dev_t pdev;
40250565Sphk
40362617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
40462617Simp	dp = pdev->si_disk;
40574206Ssos	if (!dp)
40674206Ssos		return (ENXIO);
40750565Sphk	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
40850565Sphk	if (error == ENOIOCTL)
40983366Sjulian		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td);
41050565Sphk	return (error);
41150565Sphk}
41250565Sphk
41350565Sphkstatic int
41450565Sphkdiskpsize(dev_t dev)
41550565Sphk{
41650565Sphk	struct disk *dp;
41750728Sphk	dev_t pdev;
41850565Sphk
41962617Simp	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
42062617Simp	dp = pdev->si_disk;
42162617Simp	if (!dp)
42262617Simp		return (-1);
42362617Simp	if (dp != dev->si_disk) {
42450728Sphk		dev->si_drv1 = pdev->si_drv1;
42550728Sphk		dev->si_drv2 = pdev->si_drv2;
42650728Sphk		/* XXX: don't set bp->b_dev->si_disk (?) */
42750728Sphk	}
42850565Sphk	return (dssize(dev, &dp->d_slice));
42950565Sphk}
43051111Sjulian
43151111SjulianSYSCTL_DECL(_debug_sizeof);
43251111Sjulian
43351111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
43451111Sjulian    0, sizeof(struct disklabel), "sizeof(struct disklabel)");
43551111Sjulian
43651111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
43751111Sjulian    0, sizeof(struct diskslices), "sizeof(struct diskslices)");
43851111Sjulian
43951111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
44051111Sjulian    0, sizeof(struct disk), "sizeof(struct disk)");
441