subr_disk.c revision 51198
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 51198 1999-09-12 09:16:00Z 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 <sys/vnode.h>
22#include <machine/md_var.h>
23
24MALLOC_DEFINE(M_DISK, "disk", "disk data");
25
26static d_strategy_t diskstrategy;
27static d_open_t diskopen;
28static d_close_t diskclose;
29static d_ioctl_t diskioctl;
30static d_psize_t diskpsize;
31
32dev_t
33disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw)
34{
35	dev_t dev;
36	struct cdevsw *cds;
37
38	MALLOC(cds, struct cdevsw *, sizeof(*cds), M_DISK, M_WAITOK);
39
40	bzero(dp, sizeof(*dp));
41
42	dev = makedev(cdevsw->d_maj, 0);
43	if (!devsw(dev)) {
44		dp->d_open = cdevsw->d_open;
45		cdevsw->d_open = diskopen;
46		dp->d_close = cdevsw->d_close;
47		cdevsw->d_close = diskclose;
48		dp->d_ioctl = cdevsw->d_ioctl;
49		cdevsw->d_ioctl = diskioctl;
50		dp->d_strategy = cdevsw->d_strategy;
51		cdevsw->d_strategy = diskstrategy;
52		dp->d_psize = cdevsw->d_psize;
53		cdevsw->d_psize = diskpsize;
54		cdevsw_add(cdevsw);
55	}
56
57	printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
58	dev = make_dev(cdevsw, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
59	    0, 0, 0, "r%s%d", cdevsw->d_name, unit);
60
61	dev->si_disk = dp;
62	dp->d_dev = dev;
63	dp->d_flags = flags;
64	return (dev);
65}
66
67int
68disk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
69{
70	struct disk *dp;
71	struct disklabel *dl;
72	u_int boff;
73
74	dp = dev->si_disk;
75	if (!dp)
76		return (ENXIO);
77	if (!dp->d_slice)
78		return (ENXIO);
79	dl = dsgetlabel(dev, dp->d_slice);
80	if (!dl)
81		return (ENXIO);
82	*count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize;
83	if (dumplo < 0 ||
84	    (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
85		return (EINVAL);
86	boff = dl->d_partitions[dkpart(dev)].p_offset +
87	    dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
88	*blkno = boff + dumplo;
89	*secsize = dl->d_secsize;
90	return (0);
91
92}
93
94void
95disk_invalidate (struct disk *disk)
96{
97	dsgone(&disk->d_slice);
98}
99
100void
101disk_delete(dev_t dev)
102{
103	return;
104}
105
106/*
107 * The cdevsw functions
108 */
109
110static int
111diskopen(dev_t dev, int oflags, int devtype, struct proc *p)
112{
113	dev_t pdev;
114	struct disk *dp;
115	int error;
116
117	error = 0;
118	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
119
120	dp = pdev->si_disk;
121	if (!dp)
122		return (ENXIO);
123
124	dev->si_disk = dp;
125	dev->si_drv1 = pdev->si_drv1;
126	dev->si_drv2 = pdev->si_drv2;
127
128	if (!dsisopen(dp->d_slice))
129		error = dp->d_open(dev, oflags, devtype, p);
130
131	if (error)
132		return(error);
133
134	error = dsopen(dev, devtype, dp->d_flags, &dp->d_slice, &dp->d_label);
135
136	if (!dsisopen(dp->d_slice))
137		dp->d_close(dev, oflags, devtype, p);
138
139	return(error);
140}
141
142static int
143diskclose(dev_t dev, int fflag, int devtype, struct proc *p)
144{
145	struct disk *dp;
146	int error;
147
148	error = 0;
149	dp = dev->si_disk;
150	dsclose(dev, devtype, dp->d_slice);
151	if (dsisopen(dp->d_slice))
152		error = dp->d_close(dev, fflag, devtype, p);
153	return (error);
154}
155
156static void
157diskstrategy(struct buf *bp)
158{
159	dev_t pdev;
160	struct disk *dp;
161
162	dp = bp->b_dev->si_disk;
163	if (!dp) {
164		pdev = dkmodpart(dkmodslice(bp->b_dev, WHOLE_DISK_SLICE), RAW_PART);
165		dp = pdev->si_disk;
166		bp->b_dev->si_drv1 = pdev->si_drv1;
167		bp->b_dev->si_drv2 = pdev->si_drv2;
168		/* XXX: don't set bp->b_dev->si_disk (?) */
169	} else {
170		pdev = dp->d_dev;
171	}
172
173	if (!dp) {
174		bp->b_error = ENXIO;
175		bp->b_flags |= B_ERROR;
176		biodone(bp);
177		return;
178	}
179
180	if (dscheck(bp, dp->d_slice) < 0) {
181		biodone(bp);
182		return;
183	}
184
185	dp->d_strategy(bp);
186	return;
187
188}
189
190static int
191diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
192{
193	struct disk *dp;
194	int error;
195
196	dp = dev->si_disk;
197	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
198	if (error == ENOIOCTL)
199		error = dp->d_ioctl(dev, cmd, data, fflag, p);
200	return (error);
201}
202
203static int
204diskpsize(dev_t dev)
205{
206	struct disk *dp;
207	dev_t pdev;
208
209	dp = dev->si_disk;
210	if (!dp) {
211		pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
212		dp = pdev->si_disk;
213		dev->si_drv1 = pdev->si_drv1;
214		dev->si_drv2 = pdev->si_drv2;
215		/* XXX: don't set bp->b_dev->si_disk (?) */
216	}
217	return (dssize(dev, &dp->d_slice));
218}
219
220SYSCTL_DECL(_debug_sizeof);
221
222SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
223    0, sizeof(struct disklabel), "sizeof(struct disklabel)");
224
225SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
226    0, sizeof(struct diskslices), "sizeof(struct diskslices)");
227
228SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
229    0, sizeof(struct disk), "sizeof(struct disk)");
230