xref: /freebsd/sys/kern/subr_disk.c (revision 2382fb0a84d51c40ced9f8164cd868940ed21f4a)
1da9e4f55SPoul-Henning Kamp /*
2da9e4f55SPoul-Henning Kamp  * ----------------------------------------------------------------------------
3da9e4f55SPoul-Henning Kamp  * "THE BEER-WARE LICENSE" (Revision 42):
4da9e4f55SPoul-Henning Kamp  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
5da9e4f55SPoul-Henning Kamp  * can do whatever you want with this stuff. If we meet some day, and you think
6da9e4f55SPoul-Henning Kamp  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7da9e4f55SPoul-Henning Kamp  * ----------------------------------------------------------------------------
8da9e4f55SPoul-Henning Kamp  *
9da9e4f55SPoul-Henning Kamp  * $FreeBSD$
10da9e4f55SPoul-Henning Kamp  *
11da9e4f55SPoul-Henning Kamp  */
12da9e4f55SPoul-Henning Kamp 
13417fb7f6SPoul-Henning Kamp #include "opt_geom.h"
14417fb7f6SPoul-Henning Kamp 
15da9e4f55SPoul-Henning Kamp #include <sys/param.h>
16da9e4f55SPoul-Henning Kamp #include <sys/systm.h>
17f90c382cSPoul-Henning Kamp #include <sys/stdint.h>
189626b608SPoul-Henning Kamp #include <sys/bio.h>
19da9e4f55SPoul-Henning Kamp #include <sys/conf.h>
20da9e4f55SPoul-Henning Kamp #include <sys/disk.h>
21f90c382cSPoul-Henning Kamp #ifndef GEOM
22f90c382cSPoul-Henning Kamp #include <sys/kernel.h>
23f90c382cSPoul-Henning Kamp #include <sys/sysctl.h>
24da9e4f55SPoul-Henning Kamp #include <sys/malloc.h>
25445572c1SNeil Blakey-Milner #include <sys/sysctl.h>
268684f73aSPoul-Henning Kamp #include <machine/md_var.h>
273f54a085SPoul-Henning Kamp #include <sys/ctype.h>
283f54a085SPoul-Henning Kamp 
29959b7375SPoul-Henning Kamp static MALLOC_DEFINE(M_DISK, "disk", "disk data");
30da9e4f55SPoul-Henning Kamp 
31da9e4f55SPoul-Henning Kamp static d_strategy_t diskstrategy;
32da9e4f55SPoul-Henning Kamp static d_open_t diskopen;
33da9e4f55SPoul-Henning Kamp static d_close_t diskclose;
34da9e4f55SPoul-Henning Kamp static d_ioctl_t diskioctl;
35da9e4f55SPoul-Henning Kamp static d_psize_t diskpsize;
36da9e4f55SPoul-Henning Kamp 
374bd02a56SPoul-Henning Kamp static LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist);
384bd02a56SPoul-Henning Kamp 
394e4a7663SPoul-Henning Kamp void disk_dev_synth(dev_t dev);
404e4a7663SPoul-Henning Kamp 
414e4a7663SPoul-Henning Kamp void
424e4a7663SPoul-Henning Kamp disk_dev_synth(dev_t dev)
434e4a7663SPoul-Henning Kamp {
444e4a7663SPoul-Henning Kamp 	struct disk *dp;
454e4a7663SPoul-Henning Kamp 	int u, s, p;
464e4a7663SPoul-Henning Kamp 	dev_t pdev;
474e4a7663SPoul-Henning Kamp 
4820a3b67cSPoul-Henning Kamp 	if (dksparebits(dev))
49b456f7e6SPoul-Henning Kamp 		return;
504e4a7663SPoul-Henning Kamp 	LIST_FOREACH(dp, &disklist, d_list) {
514e4a7663SPoul-Henning Kamp 		if (major(dev) != dp->d_devsw->d_maj)
524e4a7663SPoul-Henning Kamp 			continue;
534e4a7663SPoul-Henning Kamp 		u = dkunit(dev);
544e4a7663SPoul-Henning Kamp 		p = RAW_PART;
554e4a7663SPoul-Henning Kamp 		s = WHOLE_DISK_SLICE;
564e4a7663SPoul-Henning Kamp 		pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p));
574e130067SPoul-Henning Kamp 		if (pdev->si_devsw == NULL)
584e130067SPoul-Henning Kamp 			return;		/* Probably a unit we don't have */
594e4a7663SPoul-Henning Kamp 		s = dkslice(dev);
604e4a7663SPoul-Henning Kamp 		p = dkpart(dev);
614e4a7663SPoul-Henning Kamp 		if (s == WHOLE_DISK_SLICE && p == RAW_PART) {
624e4a7663SPoul-Henning Kamp 			/* XXX: actually should not happen */
634e4a7663SPoul-Henning Kamp 			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
644e4a7663SPoul-Henning Kamp 			    UID_ROOT, GID_OPERATOR, 0640, "%s%d",
654e4a7663SPoul-Henning Kamp 				dp->d_devsw->d_name, u);
664e4a7663SPoul-Henning Kamp 			dev_depends(pdev, dev);
674e4a7663SPoul-Henning Kamp 			return;
684e4a7663SPoul-Henning Kamp 		}
694e4a7663SPoul-Henning Kamp 		if (s == COMPATIBILITY_SLICE) {
704e4a7663SPoul-Henning Kamp 			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
714e4a7663SPoul-Henning Kamp 			    UID_ROOT, GID_OPERATOR, 0640, "%s%d%c",
724e4a7663SPoul-Henning Kamp 				dp->d_devsw->d_name, u, 'a' + p);
734e4a7663SPoul-Henning Kamp 			dev_depends(pdev, dev);
744e4a7663SPoul-Henning Kamp 			return;
754e4a7663SPoul-Henning Kamp 		}
76a2d7281cSPoul-Henning Kamp 		if (p != RAW_PART) {
774e4a7663SPoul-Henning Kamp 			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
784e4a7663SPoul-Henning Kamp 			    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c",
79a2d7281cSPoul-Henning Kamp 				dp->d_devsw->d_name, u, s - BASE_SLICE + 1,
80a2d7281cSPoul-Henning Kamp 				'a' + p);
81a2d7281cSPoul-Henning Kamp 		} else {
82a2d7281cSPoul-Henning Kamp 			dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
83a2d7281cSPoul-Henning Kamp 			    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d",
844e4a7663SPoul-Henning Kamp 				dp->d_devsw->d_name, u, s - BASE_SLICE + 1);
85a2d7281cSPoul-Henning Kamp 			make_dev_alias(dev, "%s%ds%dc",
86a2d7281cSPoul-Henning Kamp 			    dp->d_devsw->d_name, u, s - BASE_SLICE + 1);
87a2d7281cSPoul-Henning Kamp 		}
88a2d7281cSPoul-Henning Kamp 		dev_depends(pdev, dev);
894e4a7663SPoul-Henning Kamp 		return;
904e4a7663SPoul-Henning Kamp 	}
914e4a7663SPoul-Henning Kamp }
924e4a7663SPoul-Henning Kamp 
933f54a085SPoul-Henning Kamp static void
943f54a085SPoul-Henning Kamp disk_clone(void *arg, char *name, int namelen, dev_t *dev)
953f54a085SPoul-Henning Kamp {
963f54a085SPoul-Henning Kamp 	struct disk *dp;
973f54a085SPoul-Henning Kamp 	char const *d;
98417fb7f6SPoul-Henning Kamp 	char *e;
99417fb7f6SPoul-Henning Kamp 	int j, u, s, p;
1003f54a085SPoul-Henning Kamp 	dev_t pdev;
1013f54a085SPoul-Henning Kamp 
1023f54a085SPoul-Henning Kamp 	if (*dev != NODEV)
1033f54a085SPoul-Henning Kamp 		return;
1043f54a085SPoul-Henning Kamp 
1053f54a085SPoul-Henning Kamp 	LIST_FOREACH(dp, &disklist, d_list) {
1063f54a085SPoul-Henning Kamp 		d = dp->d_devsw->d_name;
107417fb7f6SPoul-Henning Kamp 		j = dev_stdclone(name, &e, d, &u);
108417fb7f6SPoul-Henning Kamp 		if (j == 0)
1093f54a085SPoul-Henning Kamp 			continue;
110f84ee0ffSPoul-Henning Kamp 		if (u > DKMAXUNIT)
111f84ee0ffSPoul-Henning Kamp 			continue;
1123f54a085SPoul-Henning Kamp 		p = RAW_PART;
1133f54a085SPoul-Henning Kamp 		s = WHOLE_DISK_SLICE;
1143f54a085SPoul-Henning Kamp 		pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p));
1153f54a085SPoul-Henning Kamp 		if (pdev->si_disk == NULL)
1163f54a085SPoul-Henning Kamp 			continue;
117417fb7f6SPoul-Henning Kamp 		if (*e != '\0') {
118417fb7f6SPoul-Henning Kamp 			j = dev_stdclone(e, &e, "s", &s);
119417fb7f6SPoul-Henning Kamp 			if (j == 0)
1203f54a085SPoul-Henning Kamp 				s = COMPATIBILITY_SLICE;
121417fb7f6SPoul-Henning Kamp 			else if (j == 1 || j == 2)
122417fb7f6SPoul-Henning Kamp 				s += BASE_SLICE - 1;
123417fb7f6SPoul-Henning Kamp 			if (!*e)
124417fb7f6SPoul-Henning Kamp 				;		/* ad0s1 case */
125417fb7f6SPoul-Henning Kamp 			else if (e[1] != '\0')
126417fb7f6SPoul-Henning Kamp 				return;		/* can never be a disk name */
127417fb7f6SPoul-Henning Kamp 			else if (*e < 'a' || *e > 'h')
128417fb7f6SPoul-Henning Kamp 				return;		/* can never be a disk name */
1293f54a085SPoul-Henning Kamp 			else
130417fb7f6SPoul-Henning Kamp 				p = *e - 'a';
1313f54a085SPoul-Henning Kamp 		}
132417fb7f6SPoul-Henning Kamp 		if (s == WHOLE_DISK_SLICE && p == RAW_PART) {
133417fb7f6SPoul-Henning Kamp 			return;
134417fb7f6SPoul-Henning Kamp 		} else if (s >= BASE_SLICE && p != RAW_PART) {
1354e4a7663SPoul-Henning Kamp 			*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
1364e4a7663SPoul-Henning Kamp 			    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c",
137a2d7281cSPoul-Henning Kamp 			    pdev->si_devsw->d_name, u, s - BASE_SLICE + 1,
138a2d7281cSPoul-Henning Kamp 			    p + 'a');
139a2d7281cSPoul-Henning Kamp 		} else if (s >= BASE_SLICE) {
140a2d7281cSPoul-Henning Kamp 			*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
141a2d7281cSPoul-Henning Kamp 			    UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d",
142a2d7281cSPoul-Henning Kamp 			    pdev->si_devsw->d_name, u, s - BASE_SLICE + 1);
143a2d7281cSPoul-Henning Kamp 			make_dev_alias(*dev, "%s%ds%dc",
144a2d7281cSPoul-Henning Kamp 			    pdev->si_devsw->d_name, u, s - BASE_SLICE + 1);
145a2d7281cSPoul-Henning Kamp 		} else {
1463f54a085SPoul-Henning Kamp 			*dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
147417fb7f6SPoul-Henning Kamp 			    UID_ROOT, GID_OPERATOR, 0640, "%s%d%c",
148417fb7f6SPoul-Henning Kamp 			    pdev->si_devsw->d_name, u, p + 'a');
1494e4a7663SPoul-Henning Kamp 		}
150a2d7281cSPoul-Henning Kamp 		dev_depends(pdev, *dev);
1513f54a085SPoul-Henning Kamp 		return;
1523f54a085SPoul-Henning Kamp 	}
1533f54a085SPoul-Henning Kamp }
1543f54a085SPoul-Henning Kamp 
1555d10777cSWarner Losh static void
1565d10777cSWarner Losh inherit_raw(dev_t pdev, dev_t dev)
1575d10777cSWarner Losh {
1585d10777cSWarner Losh 	dev->si_disk = pdev->si_disk;
1595d10777cSWarner Losh 	dev->si_drv1 = pdev->si_drv1;
1605d10777cSWarner Losh 	dev->si_drv2 = pdev->si_drv2;
1615d10777cSWarner Losh 	dev->si_iosize_max = pdev->si_iosize_max;
1625d10777cSWarner Losh 	dev->si_bsize_phys = pdev->si_bsize_phys;
1635d10777cSWarner Losh 	dev->si_bsize_best = pdev->si_bsize_best;
1645d10777cSWarner Losh }
1655d10777cSWarner Losh 
166da9e4f55SPoul-Henning Kamp dev_t
1672016e4e9SPoul-Henning Kamp disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
168da9e4f55SPoul-Henning Kamp {
1693f54a085SPoul-Henning Kamp 	static int once;
17022628ccfSPoul-Henning Kamp 	dev_t dev;
1713344c5a1SPoul-Henning Kamp 
1723344c5a1SPoul-Henning Kamp 	if (!once) {
1733344c5a1SPoul-Henning Kamp 		EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000);
1743344c5a1SPoul-Henning Kamp 		once++;
1753344c5a1SPoul-Henning Kamp 	}
176da9e4f55SPoul-Henning Kamp 
1778684f73aSPoul-Henning Kamp 	bzero(dp, sizeof(*dp));
1783febdd8fSPoul-Henning Kamp 
1798576c652SPoul-Henning Kamp 	if (proto->d_open != diskopen) {
1802016e4e9SPoul-Henning Kamp 		*proto = *cdevsw;
1812016e4e9SPoul-Henning Kamp 		proto->d_open = diskopen;
1822016e4e9SPoul-Henning Kamp 		proto->d_close = diskclose;
1832016e4e9SPoul-Henning Kamp 		proto->d_ioctl = diskioctl;
1842016e4e9SPoul-Henning Kamp 		proto->d_strategy = diskstrategy;
1852016e4e9SPoul-Henning Kamp 		proto->d_psize = diskpsize;
1863febdd8fSPoul-Henning Kamp 	}
1873febdd8fSPoul-Henning Kamp 
1888d67e113SJordan K. Hubbard 	if (bootverbose)
1893febdd8fSPoul-Henning Kamp 		printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
190abd1f573SPoul-Henning Kamp 	dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
1913f54a085SPoul-Henning Kamp 	    UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit);
1923febdd8fSPoul-Henning Kamp 
193da9e4f55SPoul-Henning Kamp 	dev->si_disk = dp;
194da9e4f55SPoul-Henning Kamp 	dp->d_dev = dev;
1958db34b3aSPoul-Henning Kamp 	dp->d_dsflags = flags;
1962016e4e9SPoul-Henning Kamp 	dp->d_devsw = cdevsw;
1974bd02a56SPoul-Henning Kamp 	LIST_INSERT_HEAD(&disklist, dp, d_list);
1983344c5a1SPoul-Henning Kamp 
199da9e4f55SPoul-Henning Kamp 	return (dev);
200da9e4f55SPoul-Henning Kamp }
201da9e4f55SPoul-Henning Kamp 
20281661c94SPoul-Henning Kamp static int
20381661c94SPoul-Henning Kamp diskdumpconf(u_int onoff, dev_t dev, struct disk *dp)
2048684f73aSPoul-Henning Kamp {
20581661c94SPoul-Henning Kamp 	struct dumperinfo di;
2068684f73aSPoul-Henning Kamp 	struct disklabel *dl;
2078684f73aSPoul-Henning Kamp 
20881661c94SPoul-Henning Kamp 	if (!onoff)
20981661c94SPoul-Henning Kamp 		return(set_dumper(NULL));
2108684f73aSPoul-Henning Kamp 	dl = dsgetlabel(dev, dp->d_slice);
2118684f73aSPoul-Henning Kamp 	if (!dl)
2128684f73aSPoul-Henning Kamp 		return (ENXIO);
21381661c94SPoul-Henning Kamp 	bzero(&di, sizeof di);
21481661c94SPoul-Henning Kamp 	di.dumper = (dumper_t *)dp->d_devsw->d_dump;
21581661c94SPoul-Henning Kamp 	di.priv = dp->d_dev;
21681661c94SPoul-Henning Kamp 	di.blocksize = dl->d_secsize;
21781661c94SPoul-Henning Kamp 	di.mediaoffset = (off_t)(dl->d_partitions[dkpart(dev)].p_offset +
21881661c94SPoul-Henning Kamp 	    dp->d_slice->dss_slices[dkslice(dev)].ds_offset) * DEV_BSIZE;
21981661c94SPoul-Henning Kamp 	di.mediasize =
22081661c94SPoul-Henning Kamp 	    (off_t)(dl->d_partitions[dkpart(dev)].p_size) * DEV_BSIZE;
22181661c94SPoul-Henning Kamp 	return(set_dumper(&di));
2228684f73aSPoul-Henning Kamp }
2238684f73aSPoul-Henning Kamp 
2248684f73aSPoul-Henning Kamp void
2258684f73aSPoul-Henning Kamp disk_invalidate (struct disk *disk)
2268684f73aSPoul-Henning Kamp {
22747351d27SSøren Schmidt 	if (disk->d_slice)
2288684f73aSPoul-Henning Kamp 		dsgone(&disk->d_slice);
2298684f73aSPoul-Henning Kamp }
2308684f73aSPoul-Henning Kamp 
231da9e4f55SPoul-Henning Kamp void
2321edde29eSPoul-Henning Kamp disk_destroy(dev_t dev)
233da9e4f55SPoul-Henning Kamp {
2344bd02a56SPoul-Henning Kamp 	LIST_REMOVE(dev->si_disk, d_list);
2354bd02a56SPoul-Henning Kamp 	bzero(dev->si_disk, sizeof(*dev->si_disk));
23647351d27SSøren Schmidt     	dev->si_disk = NULL;
23747351d27SSøren Schmidt 	destroy_dev(dev);
238da9e4f55SPoul-Henning Kamp 	return;
239da9e4f55SPoul-Henning Kamp }
240da9e4f55SPoul-Henning Kamp 
2414bd02a56SPoul-Henning Kamp struct disk *
2424bd02a56SPoul-Henning Kamp disk_enumerate(struct disk *disk)
2434bd02a56SPoul-Henning Kamp {
2444bd02a56SPoul-Henning Kamp 	if (!disk)
2454bd02a56SPoul-Henning Kamp 		return (LIST_FIRST(&disklist));
2464bd02a56SPoul-Henning Kamp 	else
2474bd02a56SPoul-Henning Kamp 		return (LIST_NEXT(disk, d_list));
2484bd02a56SPoul-Henning Kamp }
2494bd02a56SPoul-Henning Kamp 
250445572c1SNeil Blakey-Milner static int
25182d9ae4eSPoul-Henning Kamp sysctl_disks(SYSCTL_HANDLER_ARGS)
252445572c1SNeil Blakey-Milner {
253445572c1SNeil Blakey-Milner 	struct disk *disk;
254445572c1SNeil Blakey-Milner 	int error, first;
255445572c1SNeil Blakey-Milner 
256445572c1SNeil Blakey-Milner 	disk = NULL;
257445572c1SNeil Blakey-Milner 	first = 1;
258445572c1SNeil Blakey-Milner 
259445572c1SNeil Blakey-Milner 	while ((disk = disk_enumerate(disk))) {
260445572c1SNeil Blakey-Milner 		if (!first) {
261445572c1SNeil Blakey-Milner 			error = SYSCTL_OUT(req, " ", 1);
262445572c1SNeil Blakey-Milner 			if (error)
263445572c1SNeil Blakey-Milner 				return error;
264445572c1SNeil Blakey-Milner 		} else {
265445572c1SNeil Blakey-Milner 			first = 0;
266445572c1SNeil Blakey-Milner 		}
267445572c1SNeil Blakey-Milner 		error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name));
268445572c1SNeil Blakey-Milner 		if (error)
269445572c1SNeil Blakey-Milner 			return error;
270445572c1SNeil Blakey-Milner 	}
271445572c1SNeil Blakey-Milner 	error = SYSCTL_OUT(req, "", 1);
272445572c1SNeil Blakey-Milner 	return error;
273445572c1SNeil Blakey-Milner }
274445572c1SNeil Blakey-Milner 
27555f7c614SArchie Cobbs SYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, 0,
276445572c1SNeil Blakey-Milner     sysctl_disks, "A", "names of available disks");
277445572c1SNeil Blakey-Milner 
2788684f73aSPoul-Henning Kamp /*
2798684f73aSPoul-Henning Kamp  * The cdevsw functions
2808684f73aSPoul-Henning Kamp  */
2818684f73aSPoul-Henning Kamp 
282da9e4f55SPoul-Henning Kamp static int
283b40ce416SJulian Elischer diskopen(dev_t dev, int oflags, int devtype, struct thread *td)
284da9e4f55SPoul-Henning Kamp {
285da9e4f55SPoul-Henning Kamp 	dev_t pdev;
286da9e4f55SPoul-Henning Kamp 	struct disk *dp;
287da9e4f55SPoul-Henning Kamp 	int error;
288da9e4f55SPoul-Henning Kamp 
2898684f73aSPoul-Henning Kamp 	error = 0;
290da9e4f55SPoul-Henning Kamp 	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
2918684f73aSPoul-Henning Kamp 
292da9e4f55SPoul-Henning Kamp 	dp = pdev->si_disk;
293da9e4f55SPoul-Henning Kamp 	if (!dp)
294da9e4f55SPoul-Henning Kamp 		return (ENXIO);
2958684f73aSPoul-Henning Kamp 
2968db34b3aSPoul-Henning Kamp 	while (dp->d_flags & DISKFLAG_LOCK) {
2978db34b3aSPoul-Henning Kamp 		dp->d_flags |= DISKFLAG_WANTED;
2981b4ce5ceSPoul-Henning Kamp 		error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
2991b4ce5ceSPoul-Henning Kamp 		if (error)
3001b4ce5ceSPoul-Henning Kamp 			return (error);
3018db34b3aSPoul-Henning Kamp 	}
3028db34b3aSPoul-Henning Kamp 	dp->d_flags |= DISKFLAG_LOCK;
3038db34b3aSPoul-Henning Kamp 
30445604de3SPoul-Henning Kamp 	if (!dsisopen(dp->d_slice)) {
305dc722a14SSøren Schmidt 		if (!pdev->si_iosize_max)
30645604de3SPoul-Henning Kamp 			pdev->si_iosize_max = dev->si_iosize_max;
307b40ce416SJulian Elischer 		error = dp->d_devsw->d_open(pdev, oflags, devtype, td);
30845604de3SPoul-Henning Kamp 	}
30966c12520SPoul-Henning Kamp 
31066c12520SPoul-Henning Kamp 	/* Inherit properties from the whole/raw dev_t */
3115d10777cSWarner Losh 	inherit_raw(pdev, dev);
3128684f73aSPoul-Henning Kamp 
313da9e4f55SPoul-Henning Kamp 	if (error)
3148db34b3aSPoul-Henning Kamp 		goto out;
315da9e4f55SPoul-Henning Kamp 
3168db34b3aSPoul-Henning Kamp 	error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
317da9e4f55SPoul-Henning Kamp 
3188684f73aSPoul-Henning Kamp 	if (!dsisopen(dp->d_slice))
319b40ce416SJulian Elischer 		dp->d_devsw->d_close(pdev, oflags, devtype, td);
3208db34b3aSPoul-Henning Kamp out:
3218db34b3aSPoul-Henning Kamp 	dp->d_flags &= ~DISKFLAG_LOCK;
3228db34b3aSPoul-Henning Kamp 	if (dp->d_flags & DISKFLAG_WANTED) {
3238db34b3aSPoul-Henning Kamp 		dp->d_flags &= ~DISKFLAG_WANTED;
3248db34b3aSPoul-Henning Kamp 		wakeup(dp);
3258db34b3aSPoul-Henning Kamp 	}
3268684f73aSPoul-Henning Kamp 
327da9e4f55SPoul-Henning Kamp 	return(error);
328da9e4f55SPoul-Henning Kamp }
329da9e4f55SPoul-Henning Kamp 
330da9e4f55SPoul-Henning Kamp static int
331b40ce416SJulian Elischer diskclose(dev_t dev, int fflag, int devtype, struct thread *td)
332da9e4f55SPoul-Henning Kamp {
333da9e4f55SPoul-Henning Kamp 	struct disk *dp;
334da9e4f55SPoul-Henning Kamp 	int error;
3355d10777cSWarner Losh 	dev_t pdev;
336da9e4f55SPoul-Henning Kamp 
337da9e4f55SPoul-Henning Kamp 	error = 0;
3385d10777cSWarner Losh 	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
3395d10777cSWarner Losh 	dp = pdev->si_disk;
340b417a1a8SSøren Schmidt 	if (!dp)
341b417a1a8SSøren Schmidt 		return (ENXIO);
34246a706dcSMike Smith 	dsclose(dev, devtype, dp->d_slice);
343b417a1a8SSøren Schmidt 	if (!dsisopen(dp->d_slice))
344b40ce416SJulian Elischer 		error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td);
345da9e4f55SPoul-Henning Kamp 	return (error);
346da9e4f55SPoul-Henning Kamp }
347da9e4f55SPoul-Henning Kamp 
348da9e4f55SPoul-Henning Kamp static void
3498177437dSPoul-Henning Kamp diskstrategy(struct bio *bp)
350da9e4f55SPoul-Henning Kamp {
351da9e4f55SPoul-Henning Kamp 	dev_t pdev;
352da9e4f55SPoul-Henning Kamp 	struct disk *dp;
353da9e4f55SPoul-Henning Kamp 
3548177437dSPoul-Henning Kamp 	pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
3555d10777cSWarner Losh 	dp = pdev->si_disk;
356e0e0b661SPoul-Henning Kamp 	bp->bio_resid = bp->bio_bcount;
3575d10777cSWarner Losh 	if (dp != bp->bio_dev->si_disk)
3585d10777cSWarner Losh 		inherit_raw(pdev, bp->bio_dev);
359da9e4f55SPoul-Henning Kamp 
360da9e4f55SPoul-Henning Kamp 	if (!dp) {
361a468031cSPoul-Henning Kamp 		biofinish(bp, NULL, ENXIO);
362da9e4f55SPoul-Henning Kamp 		return;
363da9e4f55SPoul-Henning Kamp 	}
364da9e4f55SPoul-Henning Kamp 
365d685023eSPoul-Henning Kamp 	if (dscheck(bp, dp->d_slice) <= 0) {
366da9e4f55SPoul-Henning Kamp 		biodone(bp);
367da9e4f55SPoul-Henning Kamp 		return;
368da9e4f55SPoul-Henning Kamp 	}
369da9e4f55SPoul-Henning Kamp 
370079f2df3SPoul-Henning Kamp 	if (bp->bio_bcount == 0) {
371079f2df3SPoul-Henning Kamp 		biodone(bp);
372079f2df3SPoul-Henning Kamp 		return;
373079f2df3SPoul-Henning Kamp 	}
374079f2df3SPoul-Henning Kamp 
37567f3c95cSPoul-Henning Kamp 	KASSERT(dp->d_devsw != NULL, ("NULL devsw"));
37667f3c95cSPoul-Henning Kamp 	KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy"));
3772016e4e9SPoul-Henning Kamp 	dp->d_devsw->d_strategy(bp);
378da9e4f55SPoul-Henning Kamp 	return;
379da9e4f55SPoul-Henning Kamp 
380da9e4f55SPoul-Henning Kamp }
381da9e4f55SPoul-Henning Kamp 
382da9e4f55SPoul-Henning Kamp static int
383b40ce416SJulian Elischer diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
384da9e4f55SPoul-Henning Kamp {
385da9e4f55SPoul-Henning Kamp 	struct disk *dp;
386da9e4f55SPoul-Henning Kamp 	int error;
38781661c94SPoul-Henning Kamp 	u_int u;
3885d10777cSWarner Losh 	dev_t pdev;
389da9e4f55SPoul-Henning Kamp 
3905d10777cSWarner Losh 	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
3915d10777cSWarner Losh 	dp = pdev->si_disk;
392b417a1a8SSøren Schmidt 	if (!dp)
393b417a1a8SSøren Schmidt 		return (ENXIO);
3947f086a08SPoul-Henning Kamp 	if (cmd == DIOCSKERNELDUMP) {
39581661c94SPoul-Henning Kamp 		u = *(u_int *)data;
39681661c94SPoul-Henning Kamp 		return (diskdumpconf(u, dev, dp));
39781661c94SPoul-Henning Kamp 	}
3981bdb20a6SPoul-Henning Kamp 	if (cmd == DIOCGFRONTSTUFF) {
3991bdb20a6SPoul-Henning Kamp 		*(off_t *)data = 8192;	/* XXX: crude but enough) */
4001bdb20a6SPoul-Henning Kamp 		return (0);
4011bdb20a6SPoul-Henning Kamp 	}
402da9e4f55SPoul-Henning Kamp 	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
403da9e4f55SPoul-Henning Kamp 	if (error == ENOIOCTL)
404b40ce416SJulian Elischer 		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td);
405da9e4f55SPoul-Henning Kamp 	return (error);
406da9e4f55SPoul-Henning Kamp }
407da9e4f55SPoul-Henning Kamp 
408da9e4f55SPoul-Henning Kamp static int
409da9e4f55SPoul-Henning Kamp diskpsize(dev_t dev)
410da9e4f55SPoul-Henning Kamp {
411da9e4f55SPoul-Henning Kamp 	struct disk *dp;
4128684f73aSPoul-Henning Kamp 	dev_t pdev;
413da9e4f55SPoul-Henning Kamp 
4148684f73aSPoul-Henning Kamp 	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
4158684f73aSPoul-Henning Kamp 	dp = pdev->si_disk;
416a4fcac54SBruce Evans 	if (!dp)
417a4fcac54SBruce Evans 		return (-1);
4185d10777cSWarner Losh 	if (dp != dev->si_disk) {
4198684f73aSPoul-Henning Kamp 		dev->si_drv1 = pdev->si_drv1;
4208684f73aSPoul-Henning Kamp 		dev->si_drv2 = pdev->si_drv2;
4218684f73aSPoul-Henning Kamp 		/* XXX: don't set bp->b_dev->si_disk (?) */
4228684f73aSPoul-Henning Kamp 	}
423da9e4f55SPoul-Henning Kamp 	return (dssize(dev, &dp->d_slice));
424da9e4f55SPoul-Henning Kamp }
42585a219d2SJulian Elischer 
42685a219d2SJulian Elischer SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
42785a219d2SJulian Elischer     0, sizeof(struct disklabel), "sizeof(struct disklabel)");
42885a219d2SJulian Elischer 
42985a219d2SJulian Elischer SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
43085a219d2SJulian Elischer     0, sizeof(struct diskslices), "sizeof(struct diskslices)");
43185a219d2SJulian Elischer 
43285a219d2SJulian Elischer SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
43385a219d2SJulian Elischer     0, sizeof(struct disk), "sizeof(struct disk)");
434417fb7f6SPoul-Henning Kamp 
435417fb7f6SPoul-Henning Kamp #endif
436f90c382cSPoul-Henning Kamp 
437f90c382cSPoul-Henning Kamp /*-
438f90c382cSPoul-Henning Kamp  * Disk error is the preface to plaintive error messages
439f90c382cSPoul-Henning Kamp  * about failing disk transfers.  It prints messages of the form
440f90c382cSPoul-Henning Kamp  * 	"hp0g: BLABLABLA cmd=read fsbn 12345 of 12344-12347"
441f90c382cSPoul-Henning Kamp  * blkdone should be -1 if the position of the error is unknown.
442f90c382cSPoul-Henning Kamp  * The message is printed with printf.
443f90c382cSPoul-Henning Kamp  */
444f90c382cSPoul-Henning Kamp void
445f90c382cSPoul-Henning Kamp disk_err(struct bio *bp, const char *what, int blkdone, int nl)
446f90c382cSPoul-Henning Kamp {
447f90c382cSPoul-Henning Kamp 	daddr_t sn;
448f90c382cSPoul-Henning Kamp 
449f90c382cSPoul-Henning Kamp 	printf("%s: %s", devtoname(bp->bio_dev), what);
450f90c382cSPoul-Henning Kamp 	switch(bp->bio_cmd) {
451f90c382cSPoul-Henning Kamp 	case BIO_READ:		printf("cmd=read"); break;
452f90c382cSPoul-Henning Kamp 	case BIO_WRITE:		printf("cmd=write"); break;
453f90c382cSPoul-Henning Kamp 	case BIO_DELETE:	printf("cmd=delete"); break;
454f90c382cSPoul-Henning Kamp 	case BIO_GETATTR:	printf("cmd=getattr"); break;
455f90c382cSPoul-Henning Kamp 	case BIO_SETATTR:	printf("cmd=setattr"); break;
456f90c382cSPoul-Henning Kamp 	default:		printf("cmd=%x", bp->bio_cmd); break;
457f90c382cSPoul-Henning Kamp 	}
458f90c382cSPoul-Henning Kamp 	sn = bp->bio_blkno;
459f90c382cSPoul-Henning Kamp 	if (bp->bio_bcount <= DEV_BSIZE) {
460f90c382cSPoul-Henning Kamp 		printf("fsbn %jd%s", (intmax_t)sn, nl ? "\n" : "");
461f90c382cSPoul-Henning Kamp 		return;
462f90c382cSPoul-Henning Kamp 	}
463f90c382cSPoul-Henning Kamp 	if (blkdone >= 0) {
464f90c382cSPoul-Henning Kamp 		sn += blkdone;
465f90c382cSPoul-Henning Kamp 		printf("fsbn %jd of ", (intmax_t)sn);
466f90c382cSPoul-Henning Kamp 	}
467f90c382cSPoul-Henning Kamp 	printf("%jd-%jd", (intmax_t)bp->bio_blkno,
468f90c382cSPoul-Henning Kamp 	    (intmax_t)(bp->bio_blkno + (bp->bio_bcount - 1) / DEV_BSIZE));
469f90c382cSPoul-Henning Kamp 	if (nl)
470f90c382cSPoul-Henning Kamp 		printf("\n");
471f90c382cSPoul-Henning Kamp }
4722382fb0aSPoul-Henning Kamp 
4732382fb0aSPoul-Henning Kamp #ifdef notquite
4742382fb0aSPoul-Henning Kamp /*
4752382fb0aSPoul-Henning Kamp  * Mutex to use when delaying niced I/O bound processes in bioq_disksort().
4762382fb0aSPoul-Henning Kamp  */
4772382fb0aSPoul-Henning Kamp static struct mtx dksort_mtx;
4782382fb0aSPoul-Henning Kamp static void
4792382fb0aSPoul-Henning Kamp dksort_init(void)
4802382fb0aSPoul-Henning Kamp {
4812382fb0aSPoul-Henning Kamp 
4822382fb0aSPoul-Henning Kamp 	mtx_init(&dksort_mtx, "dksort", NULL, MTX_DEF);
4832382fb0aSPoul-Henning Kamp }
4842382fb0aSPoul-Henning Kamp SYSINIT(dksort, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dksort_init, NULL)
4852382fb0aSPoul-Henning Kamp #endif
4862382fb0aSPoul-Henning Kamp 
4872382fb0aSPoul-Henning Kamp /*
4882382fb0aSPoul-Henning Kamp  * Seek sort for disks.
4892382fb0aSPoul-Henning Kamp  *
4902382fb0aSPoul-Henning Kamp  * The buf_queue keep two queues, sorted in ascending block order.  The first
4912382fb0aSPoul-Henning Kamp  * queue holds those requests which are positioned after the current block
4922382fb0aSPoul-Henning Kamp  * (in the first request); the second, which starts at queue->switch_point,
4932382fb0aSPoul-Henning Kamp  * holds requests which came in after their block number was passed.  Thus
4942382fb0aSPoul-Henning Kamp  * we implement a one way scan, retracting after reaching the end of the drive
4952382fb0aSPoul-Henning Kamp  * to the first request on the second queue, at which time it becomes the
4962382fb0aSPoul-Henning Kamp  * first queue.
4972382fb0aSPoul-Henning Kamp  *
4982382fb0aSPoul-Henning Kamp  * A one-way scan is natural because of the way UNIX read-ahead blocks are
4992382fb0aSPoul-Henning Kamp  * allocated.
5002382fb0aSPoul-Henning Kamp  */
5012382fb0aSPoul-Henning Kamp 
5022382fb0aSPoul-Henning Kamp void
5032382fb0aSPoul-Henning Kamp bioq_disksort(bioq, bp)
5042382fb0aSPoul-Henning Kamp 	struct bio_queue_head *bioq;
5052382fb0aSPoul-Henning Kamp 	struct bio *bp;
5062382fb0aSPoul-Henning Kamp {
5072382fb0aSPoul-Henning Kamp 	struct bio *bq;
5082382fb0aSPoul-Henning Kamp 	struct bio *bn;
5092382fb0aSPoul-Henning Kamp 	struct bio *be;
5102382fb0aSPoul-Henning Kamp 
5112382fb0aSPoul-Henning Kamp #ifdef notquite
5122382fb0aSPoul-Henning Kamp 	struct thread *td = curthread;
5132382fb0aSPoul-Henning Kamp 
5142382fb0aSPoul-Henning Kamp 	if (td && td->td_ksegrp->kg_nice > 0) {
5152382fb0aSPoul-Henning Kamp 		TAILQ_FOREACH(bn, &bioq->queue, bio_queue)
5162382fb0aSPoul-Henning Kamp 			if (BIOTOBUF(bp)->b_vp != BIOTOBUF(bn)->b_vp)
5172382fb0aSPoul-Henning Kamp 				break;
5182382fb0aSPoul-Henning Kamp 		if (bn != NULL) {
5192382fb0aSPoul-Henning Kamp 			mtx_lock(&dksort_mtx);
5202382fb0aSPoul-Henning Kamp 			msleep(&dksort_mtx, &dksort_mtx,
5212382fb0aSPoul-Henning Kamp 			    PPAUSE | PCATCH | PDROP, "ioslow",
5222382fb0aSPoul-Henning Kamp 			    td->td_ksegrp->kg_nice);
5232382fb0aSPoul-Henning Kamp 		}
5242382fb0aSPoul-Henning Kamp 	}
5252382fb0aSPoul-Henning Kamp #endif
5262382fb0aSPoul-Henning Kamp 	if (!atomic_cmpset_int(&bioq->busy, 0, 1))
5272382fb0aSPoul-Henning Kamp 		panic("Recursing in bioq_disksort()");
5282382fb0aSPoul-Henning Kamp 	be = TAILQ_LAST(&bioq->queue, bio_queue);
5292382fb0aSPoul-Henning Kamp 	/*
5302382fb0aSPoul-Henning Kamp 	 * If the queue is empty or we are an
5312382fb0aSPoul-Henning Kamp 	 * ordered transaction, then it's easy.
5322382fb0aSPoul-Henning Kamp 	 */
5332382fb0aSPoul-Henning Kamp 	if ((bq = bioq_first(bioq)) == NULL) {
5342382fb0aSPoul-Henning Kamp 		bioq_insert_tail(bioq, bp);
5352382fb0aSPoul-Henning Kamp 		bioq->busy = 0;
5362382fb0aSPoul-Henning Kamp 		return;
5372382fb0aSPoul-Henning Kamp 	} else if (bioq->insert_point != NULL) {
5382382fb0aSPoul-Henning Kamp 
5392382fb0aSPoul-Henning Kamp 		/*
5402382fb0aSPoul-Henning Kamp 		 * A certain portion of the list is
5412382fb0aSPoul-Henning Kamp 		 * "locked" to preserve ordering, so
5422382fb0aSPoul-Henning Kamp 		 * we can only insert after the insert
5432382fb0aSPoul-Henning Kamp 		 * point.
5442382fb0aSPoul-Henning Kamp 		 */
5452382fb0aSPoul-Henning Kamp 		bq = bioq->insert_point;
5462382fb0aSPoul-Henning Kamp 	} else {
5472382fb0aSPoul-Henning Kamp 
5482382fb0aSPoul-Henning Kamp 		/*
5492382fb0aSPoul-Henning Kamp 		 * If we lie before the last removed (currently active)
5502382fb0aSPoul-Henning Kamp 		 * request, and are not inserting ourselves into the
5512382fb0aSPoul-Henning Kamp 		 * "locked" portion of the list, then we must add ourselves
5522382fb0aSPoul-Henning Kamp 		 * to the second request list.
5532382fb0aSPoul-Henning Kamp 		 */
5542382fb0aSPoul-Henning Kamp 		if (bp->bio_pblkno < bioq->last_pblkno) {
5552382fb0aSPoul-Henning Kamp 
5562382fb0aSPoul-Henning Kamp 			bq = bioq->switch_point;
5572382fb0aSPoul-Henning Kamp 			/*
5582382fb0aSPoul-Henning Kamp 			 * If we are starting a new secondary list,
5592382fb0aSPoul-Henning Kamp 			 * then it's easy.
5602382fb0aSPoul-Henning Kamp 			 */
5612382fb0aSPoul-Henning Kamp 			if (bq == NULL) {
5622382fb0aSPoul-Henning Kamp 				bioq->switch_point = bp;
5632382fb0aSPoul-Henning Kamp 				bioq_insert_tail(bioq, bp);
5642382fb0aSPoul-Henning Kamp 				bioq->busy = 0;
5652382fb0aSPoul-Henning Kamp 				return;
5662382fb0aSPoul-Henning Kamp 			}
5672382fb0aSPoul-Henning Kamp 			/*
5682382fb0aSPoul-Henning Kamp 			 * If we lie ahead of the current switch point,
5692382fb0aSPoul-Henning Kamp 			 * insert us before the switch point and move
5702382fb0aSPoul-Henning Kamp 			 * the switch point.
5712382fb0aSPoul-Henning Kamp 			 */
5722382fb0aSPoul-Henning Kamp 			if (bp->bio_pblkno < bq->bio_pblkno) {
5732382fb0aSPoul-Henning Kamp 				bioq->switch_point = bp;
5742382fb0aSPoul-Henning Kamp 				TAILQ_INSERT_BEFORE(bq, bp, bio_queue);
5752382fb0aSPoul-Henning Kamp 				bioq->busy = 0;
5762382fb0aSPoul-Henning Kamp 				return;
5772382fb0aSPoul-Henning Kamp 			}
5782382fb0aSPoul-Henning Kamp 		} else {
5792382fb0aSPoul-Henning Kamp 			if (bioq->switch_point != NULL)
5802382fb0aSPoul-Henning Kamp 				be = TAILQ_PREV(bioq->switch_point,
5812382fb0aSPoul-Henning Kamp 						bio_queue, bio_queue);
5822382fb0aSPoul-Henning Kamp 			/*
5832382fb0aSPoul-Henning Kamp 			 * If we lie between last_pblkno and bq,
5842382fb0aSPoul-Henning Kamp 			 * insert before bq.
5852382fb0aSPoul-Henning Kamp 			 */
5862382fb0aSPoul-Henning Kamp 			if (bp->bio_pblkno < bq->bio_pblkno) {
5872382fb0aSPoul-Henning Kamp 				TAILQ_INSERT_BEFORE(bq, bp, bio_queue);
5882382fb0aSPoul-Henning Kamp 				bioq->busy = 0;
5892382fb0aSPoul-Henning Kamp 				return;
5902382fb0aSPoul-Henning Kamp 			}
5912382fb0aSPoul-Henning Kamp 		}
5922382fb0aSPoul-Henning Kamp 	}
5932382fb0aSPoul-Henning Kamp 
5942382fb0aSPoul-Henning Kamp 	/*
5952382fb0aSPoul-Henning Kamp 	 * Request is at/after our current position in the list.
5962382fb0aSPoul-Henning Kamp 	 * Optimize for sequential I/O by seeing if we go at the tail.
5972382fb0aSPoul-Henning Kamp 	 */
5982382fb0aSPoul-Henning Kamp 	if (bp->bio_pblkno > be->bio_pblkno) {
5992382fb0aSPoul-Henning Kamp 		TAILQ_INSERT_AFTER(&bioq->queue, be, bp, bio_queue);
6002382fb0aSPoul-Henning Kamp 		bioq->busy = 0;
6012382fb0aSPoul-Henning Kamp 		return;
6022382fb0aSPoul-Henning Kamp 	}
6032382fb0aSPoul-Henning Kamp 
6042382fb0aSPoul-Henning Kamp 	/* Otherwise, insertion sort */
6052382fb0aSPoul-Henning Kamp 	while ((bn = TAILQ_NEXT(bq, bio_queue)) != NULL) {
6062382fb0aSPoul-Henning Kamp 
6072382fb0aSPoul-Henning Kamp 		/*
6082382fb0aSPoul-Henning Kamp 		 * We want to go after the current request if it is the end
6092382fb0aSPoul-Henning Kamp 		 * of the first request list, or if the next request is a
6102382fb0aSPoul-Henning Kamp 		 * larger cylinder than our request.
6112382fb0aSPoul-Henning Kamp 		 */
6122382fb0aSPoul-Henning Kamp 		if (bn == bioq->switch_point
6132382fb0aSPoul-Henning Kamp 		 || bp->bio_pblkno < bn->bio_pblkno)
6142382fb0aSPoul-Henning Kamp 			break;
6152382fb0aSPoul-Henning Kamp 		bq = bn;
6162382fb0aSPoul-Henning Kamp 	}
6172382fb0aSPoul-Henning Kamp 	TAILQ_INSERT_AFTER(&bioq->queue, bq, bp, bio_queue);
6182382fb0aSPoul-Henning Kamp 	bioq->busy = 0;
6192382fb0aSPoul-Henning Kamp }
6202382fb0aSPoul-Henning Kamp 
6212382fb0aSPoul-Henning Kamp 
622