subr_disk.c revision 76324
142421Syokota/*
242421Syokota * ----------------------------------------------------------------------------
342421Syokota * "THE BEER-WARE LICENSE" (Revision 42):
442421Syokota * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
542421Syokota * can do whatever you want with this stuff. If we meet some day, and you think
642421Syokota * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
742421Syokota * ----------------------------------------------------------------------------
842421Syokota *
942421Syokota * $FreeBSD: head/sys/kern/subr_disk.c 76324 2001-05-06 21:55:22Z phk $
1042421Syokota *
1142421Syokota */
1242421Syokota
1342421Syokota#include <sys/param.h>
1442421Syokota#include <sys/systm.h>
1542421Syokota#include <sys/kernel.h>
1642421Syokota#include <sys/sysctl.h>
1742421Syokota#include <sys/bio.h>
1842421Syokota#include <sys/conf.h>
1942421Syokota#include <sys/disk.h>
2042421Syokota#include <sys/malloc.h>
2142421Syokota#include <sys/sysctl.h>
2242421Syokota#include <machine/md_var.h>
2342421Syokota#include <sys/ctype.h>
2442421Syokota
2542421Syokotastatic MALLOC_DEFINE(M_DISK, "disk", "disk data");
2642421Syokota
2742421Syokotastatic d_strategy_t diskstrategy;
28119418Sobrienstatic d_open_t diskopen;
29119418Sobrienstatic d_close_t diskclose;
30119418Sobrienstatic d_ioctl_t diskioctl;
3142421Syokotastatic d_psize_t diskpsize;
3242421Syokota
3342421Syokotastatic LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist);
3442421Syokota
3542421Syokotastatic void
3642421Syokotadisk_clone(void *arg, char *name, int namelen, dev_t *dev)
3742421Syokota{
38139193Sphk	struct disk *dp;
3942421Syokota	char const *d;
4042421Syokota	int i, u, s, p;
41112050Sdwmalone	dev_t pdev;
42112050Sdwmalone
4342421Syokota	if (*dev != NODEV)
4442421Syokota		return;
4566834Sphk
4642421Syokota	LIST_FOREACH(dp, &disklist, d_list) {
4742421Syokota		d = dp->d_devsw->d_name;
4842421Syokota		i = strlen(d);
4950154Syokota		if (bcmp(d, name, i) != 0)
5050154Syokota			continue;
5150154Syokota		u = 0;
5250154Syokota		if (!isdigit(name[i]))
5350154Syokota			continue;
5450154Syokota		while (isdigit(name[i])) {
5550154Syokota			u *= 10;
5650154Syokota			u += name[i++] - '0';
5750154Syokota		}
5860938Sjake		if (u > DKMAXUNIT)
59127751Sdes			continue;
6054545Syokota		p = RAW_PART;
6178161Speter		s = WHOLE_DISK_SLICE;
6278161Speter		pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p));
6342421Syokota		if (pdev->si_disk == NULL)
6442421Syokota			continue;
6542421Syokota		if (name[i] != '\0') {
6642421Syokota			if (name[i] == 's') {
6742421Syokota				s = 0;
6842421Syokota				i++;
6942421Syokota				if (!isdigit(name[i]))
7042564Syokota					continue;
7142564Syokota				while (isdigit(name[i])) {
7242421Syokota					s *= 10;
7342564Syokota					s += name[i++] - '0';
7442421Syokota				}
7542421Syokota				s += BASE_SLICE - 1;
7642421Syokota			} else {
77112050Sdwmalone				s = COMPATIBILITY_SLICE;
78112050Sdwmalone			}
79112050Sdwmalone			if (name[i] == '\0')
80112050Sdwmalone				;
81112050Sdwmalone			else if (name[i] < 'a' || name[i] > 'h')
8242421Syokota				continue;
8342421Syokota			else
8444628Syokota				p = name[i] - 'a';
8542421Syokota		}
8642421Syokota
8742421Syokota		*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
8842421Syokota		    UID_ROOT, GID_OPERATOR, 0640, name);
8942421Syokota		return;
9042421Syokota	}
9142421Syokota}
9242421Syokota
9342421Syokotastatic void
9469781Sdwmaloneinherit_raw(dev_t pdev, dev_t dev)
9544628Syokota{
9644628Syokota	dev->si_disk = pdev->si_disk;
97127752Sdes	dev->si_drv1 = pdev->si_drv1;
9844628Syokota	dev->si_drv2 = pdev->si_drv2;
9969781Sdwmalone	dev->si_iosize_max = pdev->si_iosize_max;
10069781Sdwmalone	dev->si_bsize_phys = pdev->si_bsize_phys;
10144628Syokota	dev->si_bsize_best = pdev->si_bsize_best;
10244628Syokota}
10344628Syokota
104127752Sdesdev_t
10544628Syokotadisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
10642421Syokota{
10742421Syokota	static int once;
10842421Syokota	dev_t dev;
10942421Syokota
11042421Syokota	bzero(dp, sizeof(*dp));
11142421Syokota
11242421Syokota	dev = makedev(cdevsw->d_maj, 0);
11342421Syokota	if (!devsw(dev)) {
11442421Syokota		*proto = *cdevsw;
11542421Syokota		proto->d_open = diskopen;
11642421Syokota		proto->d_close = diskclose;
11742421Syokota		proto->d_ioctl = diskioctl;
11842421Syokota		proto->d_strategy = diskstrategy;
11944628Syokota		proto->d_psize = diskpsize;
120127752Sdes		cdevsw_add(proto);
12142421Syokota	}
12242421Syokota
12342421Syokota	if (bootverbose)
12442421Syokota		printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
12542421Syokota	dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
12642421Syokota	    UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit);
12742421Syokota
12842421Syokota	dev->si_disk = dp;
12942421Syokota	dp->d_dev = dev;
13042421Syokota	dp->d_dsflags = flags;
13142421Syokota	dp->d_devsw = cdevsw;
13242421Syokota	LIST_INSERT_HEAD(&disklist, dp, d_list);
13342421Syokota	if (!once) {
13442421Syokota		EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000);
13542421Syokota		once++;
13642421Syokota	}
13742421Syokota	return (dev);
13842421Syokota}
13944628Syokota
14042421Syokotaint
14142421Syokotadisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
14242421Syokota{
14342421Syokota	struct disk *dp;
14442421Syokota	struct disklabel *dl;
14542421Syokota	u_int boff;
14642421Syokota
14742421Syokota	dp = dev->si_disk;
14844628Syokota	if (!dp)
14944628Syokota		return (ENXIO);
15054382Syokota	if (!dp->d_slice)
15180040Syokota		return (ENXIO);
15242421Syokota	dl = dsgetlabel(dev, dp->d_slice);
15342421Syokota	if (!dl)
15442421Syokota		return (ENXIO);
15542421Syokota	*count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize;
15642421Syokota	if (dumplo < 0 ||
15742421Syokota	    (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
15842421Syokota		return (EINVAL);
15942421Syokota	boff = dl->d_partitions[dkpart(dev)].p_offset +
16042421Syokota	    dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
16142421Syokota	*blkno = boff + dumplo;
16242421Syokota	*secsize = dl->d_secsize;
16342421Syokota	return (0);
16454545Syokota
16554545Syokota}
16654545Syokota
16754545Syokotavoid
16854545Syokotadisk_invalidate (struct disk *disk)
169127752Sdes{
17054545Syokota	if (disk->d_slice)
171127752Sdes		dsgone(&disk->d_slice);
17254545Syokota}
17354545Syokota
17454545Syokotavoid
17554545Syokotadisk_destroy(dev_t dev)
17654545Syokota{
17760938Sjake	LIST_REMOVE(dev->si_disk, d_list);
17854545Syokota	bzero(dev->si_disk, sizeof(*dev->si_disk));
179127752Sdes    	dev->si_disk = NULL;
18054545Syokota	destroy_dev(dev);
18154545Syokota	return;
18242421Syokota}
18342421Syokota
18442421Syokotastruct disk *
18542421Syokotadisk_enumerate(struct disk *disk)
18647295Syokota{
18747295Syokota	if (!disk)
188156126Semax		return (LIST_FIRST(&disklist));
189156126Semax	else
19042421Syokota		return (LIST_NEXT(disk, d_list));
19142421Syokota}
192156126Semax
193156126Semaxstatic int
19442421Syokotasysctl_disks(SYSCTL_HANDLER_ARGS)
19542421Syokota{
19642421Syokota	struct disk *disk;
19742421Syokota	int error, first;
19844628Syokota
19944628Syokota	disk = NULL;
200127752Sdes	first = 1;
20144628Syokota
20242421Syokota	while ((disk = disk_enumerate(disk))) {
20342421Syokota		if (!first) {
20442421Syokota			error = SYSCTL_OUT(req, " ", 1);
20542421Syokota			if (error)
20642421Syokota				return error;
20742421Syokota		} else {
20842421Syokota			first = 0;
20942421Syokota		}
21042421Syokota		error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name));
21154545Syokota		if (error)
21254545Syokota			return error;
21354545Syokota	}
21454545Syokota	error = SYSCTL_OUT(req, "", 1);
215156126Semax	return error;
216156126Semax}
217156126Semax
218156126SemaxSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL,
219156126Semax    sysctl_disks, "A", "names of available disks");
220156126Semax
221156126Semax/*
222156126Semax * The cdevsw functions
223156126Semax */
224156126Semax
225127752Sdesstatic int
22654545Syokotadiskopen(dev_t dev, int oflags, int devtype, struct proc *p)
22754545Syokota{
22878161Speter	dev_t pdev;
22978161Speter	struct disk *dp;
23042421Syokota	int error;
23142421Syokota
23242421Syokota	error = 0;
233156126Semax	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
234156126Semax
235156126Semax	dp = pdev->si_disk;
236156126Semax	if (!dp)
237156126Semax		return (ENXIO);
238156126Semax
239156126Semax	while (dp->d_flags & DISKFLAG_LOCK) {
240156126Semax		dp->d_flags |= DISKFLAG_WANTED;
241156126Semax		error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
242156126Semax		if (error)
243127752Sdes			return (error);
24442421Syokota	}
24542421Syokota	dp->d_flags |= DISKFLAG_LOCK;
24642421Syokota
247127752Sdes	if (!dsisopen(dp->d_slice)) {
24842421Syokota		if (!pdev->si_iosize_max)
24942421Syokota			pdev->si_iosize_max = dev->si_iosize_max;
25042421Syokota		error = dp->d_devsw->d_open(pdev, oflags, devtype, p);
25142421Syokota	}
25242421Syokota
25342421Syokota	/* Inherit properties from the whole/raw dev_t */
25442421Syokota	inherit_raw(pdev, dev);
25542421Syokota
25642421Syokota	if (error)
257127752Sdes		goto out;
25842421Syokota
259127752Sdes	error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
26042421Syokota
26142421Syokota	if (!dsisopen(dp->d_slice))
26242421Syokota		dp->d_devsw->d_close(pdev, oflags, devtype, p);
26342421Syokotaout:
264127752Sdes	dp->d_flags &= ~DISKFLAG_LOCK;
26542421Syokota	if (dp->d_flags & DISKFLAG_WANTED) {
26642421Syokota		dp->d_flags &= ~DISKFLAG_WANTED;
267127752Sdes		wakeup(dp);
26842421Syokota	}
26942421Syokota
27042421Syokota	return(error);
271127752Sdes}
27242421Syokota
27342421Syokotastatic int
27442421Syokotadiskclose(dev_t dev, int fflag, int devtype, struct proc *p)
27542421Syokota{
27642421Syokota	struct disk *dp;
27742421Syokota	int error;
27842421Syokota	dev_t pdev;
279127752Sdes
28042421Syokota	error = 0;
28142421Syokota	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
28242421Syokota	dp = pdev->si_disk;
28342421Syokota	if (!dp)
28442421Syokota		return (ENXIO);
28542421Syokota	dsclose(dev, devtype, dp->d_slice);
28647295Syokota	if (!dsisopen(dp->d_slice))
28747295Syokota		error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p);
28842421Syokota	return (error);
28954545Syokota}
29054545Syokota
291127752Sdesstatic void
29254545Syokotadiskstrategy(struct bio *bp)
29378161Speter{
29478161Speter	dev_t pdev;
29542421Syokota	struct disk *dp;
296127752Sdes
29742421Syokota	pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
29842421Syokota	dp = pdev->si_disk;
299127752Sdes	if (dp != bp->bio_dev->si_disk)
30042421Syokota		inherit_raw(pdev, bp->bio_dev);
30142421Syokota
30242421Syokota	if (!dp) {
30342421Syokota		biofinish(bp, NULL, ENXIO);
30442421Syokota		return;
30542421Syokota	}
30642421Syokota
30742421Syokota	if (dscheck(bp, dp->d_slice) <= 0) {
30842421Syokota		biodone(bp);
309147980Semax		return;
310147980Semax	}
311147980Semax
312147980Semax	if (bp->bio_bcount == 0) {
31342421Syokota		bp->bio_resid = 0;
314147980Semax		biodone(bp);
31542421Syokota		return;
31642421Syokota	}
31742421Syokota
318147980Semax	KASSERT(dp->d_devsw != NULL, ("NULL devsw"));
319147980Semax	KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy"));
320147980Semax	dp->d_devsw->d_strategy(bp);
321147980Semax	return;
32242421Syokota
32342421Syokota}
32442421Syokota
32542421Syokotastatic int
32642421Syokotadiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
32742421Syokota{
32842421Syokota	struct disk *dp;
32942421Syokota	int error;
330127752Sdes	dev_t pdev;
33142421Syokota
332147980Semax	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
333127752Sdes	dp = pdev->si_disk;
33442421Syokota	if (!dp)
33542421Syokota		return (ENXIO);
336147980Semax	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
337147980Semax	if (error == ENOIOCTL)
338147980Semax		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p);
339147980Semax	return (error);
340147980Semax}
341147980Semax
342147980Semaxstatic int
34342421Syokotadiskpsize(dev_t dev)
34442421Syokota{
34542421Syokota	struct disk *dp;
34642421Syokota	dev_t pdev;
34742421Syokota
34842421Syokota	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
34942421Syokota	dp = pdev->si_disk;
35042421Syokota	if (!dp)
35142421Syokota		return (-1);
352127752Sdes	if (dp != dev->si_disk) {
35342421Syokota		dev->si_drv1 = pdev->si_drv1;
35442421Syokota		dev->si_drv2 = pdev->si_drv2;
35542421Syokota		/* XXX: don't set bp->b_dev->si_disk (?) */
35642421Syokota	}
35742421Syokota	return (dssize(dev, &dp->d_slice));
35842421Syokota}
359127752Sdes
36042421SyokotaSYSCTL_DECL(_debug_sizeof);
36142421Syokota
36242421SyokotaSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
36342421Syokota    0, sizeof(struct disklabel), "sizeof(struct disklabel)");
36442421Syokota
36542421SyokotaSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
36642421Syokota    0, sizeof(struct diskslices), "sizeof(struct diskslices)");
36742421Syokota
368127752SdesSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
36942421Syokota    0, sizeof(struct disk), "sizeof(struct disk)");
37042421Syokota