subr_disk.c revision 59249
1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 *
9 * $FreeBSD: head/sys/kern/subr_disk.c 59249 2000-04-15 05:54:02Z phk $
10 *
11 */
12
13#include <sys/param.h>
14#include <sys/systm.h>
15#include <sys/kernel.h>
16#include <sys/sysctl.h>
17#include <sys/buf.h>
18#include <sys/conf.h>
19#include <sys/disk.h>
20#include <sys/malloc.h>
21#include <machine/md_var.h>
22
23MALLOC_DEFINE(M_DISK, "disk", "disk data");
24
25static d_strategy_t diskstrategy;
26static d_open_t diskopen;
27static d_close_t diskclose;
28static d_ioctl_t diskioctl;
29static d_psize_t diskpsize;
30
31dev_t
32disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
33{
34	dev_t dev;
35
36	bzero(dp, sizeof(*dp));
37
38	dev = makedev(cdevsw->d_maj, 0);
39	if (!devsw(dev)) {
40		*proto = *cdevsw;
41		proto->d_open = diskopen;
42		proto->d_close = diskclose;
43		proto->d_ioctl = diskioctl;
44		proto->d_strategy = diskstrategy;
45		proto->d_psize = diskpsize;
46		cdevsw_add(proto);
47	}
48
49	if (bootverbose)
50		printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
51	dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
52	    0, 0, 0, "r%s%d", cdevsw->d_name, unit);
53
54	dev->si_disk = dp;
55	dp->d_dev = dev;
56	dp->d_dsflags = flags;
57	dp->d_devsw = cdevsw;
58	return (dev);
59}
60
61int
62disk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
63{
64	struct disk *dp;
65	struct disklabel *dl;
66	u_int boff;
67
68	dp = dev->si_disk;
69	if (!dp)
70		return (ENXIO);
71	if (!dp->d_slice)
72		return (ENXIO);
73	dl = dsgetlabel(dev, dp->d_slice);
74	if (!dl)
75		return (ENXIO);
76	*count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize;
77	if (dumplo < 0 ||
78	    (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
79		return (EINVAL);
80	boff = dl->d_partitions[dkpart(dev)].p_offset +
81	    dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
82	*blkno = boff + dumplo;
83	*secsize = dl->d_secsize;
84	return (0);
85
86}
87
88void
89disk_invalidate (struct disk *disk)
90{
91	if (disk->d_slice)
92		dsgone(&disk->d_slice);
93}
94
95void
96disk_destroy(dev_t dev)
97{
98    	dev->si_disk = NULL;
99	destroy_dev(dev);
100	return;
101}
102
103/*
104 * The cdevsw functions
105 */
106
107static int
108diskopen(dev_t dev, int oflags, int devtype, struct proc *p)
109{
110	dev_t pdev;
111	struct disk *dp;
112	int error;
113
114	error = 0;
115	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
116
117	dp = pdev->si_disk;
118	if (!dp)
119		return (ENXIO);
120
121	while (dp->d_flags & DISKFLAG_LOCK) {
122		dp->d_flags |= DISKFLAG_WANTED;
123		error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
124		if (error)
125			return (error);
126	}
127	dp->d_flags |= DISKFLAG_LOCK;
128
129	if (!dsisopen(dp->d_slice)) {
130		if (!pdev->si_iosize_max)
131			pdev->si_iosize_max = dev->si_iosize_max;
132		error = dp->d_devsw->d_open(pdev, oflags, devtype, p);
133	}
134
135	/* Inherit properties from the whole/raw dev_t */
136	dev->si_disk = pdev->si_disk;
137	dev->si_drv1 = pdev->si_drv1;
138	dev->si_drv2 = pdev->si_drv2;
139	dev->si_iosize_max = pdev->si_iosize_max;
140	dev->si_bsize_phys = pdev->si_bsize_phys;
141	dev->si_bsize_best = pdev->si_bsize_best;
142
143	if (error)
144		goto out;
145
146	error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
147
148	if (!dsisopen(dp->d_slice))
149		dp->d_devsw->d_close(pdev, oflags, devtype, p);
150out:
151	dp->d_flags &= ~DISKFLAG_LOCK;
152	if (dp->d_flags & DISKFLAG_WANTED) {
153		dp->d_flags &= ~DISKFLAG_WANTED;
154		wakeup(dp);
155	}
156
157	return(error);
158}
159
160static int
161diskclose(dev_t dev, int fflag, int devtype, struct proc *p)
162{
163	struct disk *dp;
164	int error;
165
166	error = 0;
167	dp = dev->si_disk;
168	dsclose(dev, devtype, dp->d_slice);
169	if (!dsisopen(dp->d_slice)) {
170		error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p);
171	}
172	return (error);
173}
174
175static void
176diskstrategy(struct bio *bp)
177{
178	dev_t pdev;
179	struct disk *dp;
180
181	dp = bp->bio_dev->si_disk;
182	if (!dp) {
183		pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
184		dp = bp->bio_dev->si_disk = pdev->si_disk;
185		bp->bio_dev->si_drv1 = pdev->si_drv1;
186		bp->bio_dev->si_drv2 = pdev->si_drv2;
187		bp->bio_dev->si_iosize_max = pdev->si_iosize_max;
188		bp->bio_dev->si_bsize_phys = pdev->si_bsize_phys;
189		bp->bio_dev->si_bsize_best = pdev->si_bsize_best;
190	}
191
192	if (!dp) {
193		bp->bio_error = ENXIO;
194		bp->bio_flags |= BIO_ERROR;
195		biodone(bp);
196		return;
197	}
198
199	if (dscheck(bp, dp->d_slice) <= 0) {
200		biodone(bp);
201		return;
202	}
203
204	dp->d_devsw->d_strategy(bp);
205	return;
206
207}
208
209static int
210diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
211{
212	struct disk *dp;
213	int error;
214
215	dp = dev->si_disk;
216	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
217	if (error == ENOIOCTL)
218		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p);
219	return (error);
220}
221
222static int
223diskpsize(dev_t dev)
224{
225	struct disk *dp;
226	dev_t pdev;
227
228	dp = dev->si_disk;
229	if (!dp) {
230		pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
231		dp = pdev->si_disk;
232		if (!dp)
233			return (-1);
234		dev->si_drv1 = pdev->si_drv1;
235		dev->si_drv2 = pdev->si_drv2;
236		/* XXX: don't set bp->b_dev->si_disk (?) */
237	}
238	return (dssize(dev, &dp->d_slice));
239}
240
241SYSCTL_DECL(_debug_sizeof);
242
243SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
244    0, sizeof(struct disklabel), "sizeof(struct disklabel)");
245
246SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
247    0, sizeof(struct diskslices), "sizeof(struct diskslices)");
248
249SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
250    0, sizeof(struct disk), "sizeof(struct disk)");
251