subr_disk.c revision 51878
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 51878 1999-10-02 20:21:49Z sos $
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, struct cdevsw *proto)
34{
35	dev_t dev;
36
37	bzero(dp, sizeof(*dp));
38
39	dev = makedev(cdevsw->d_maj, 0);
40	if (!devsw(dev)) {
41		*proto = *cdevsw;
42		proto->d_open = diskopen;
43		proto->d_close = diskclose;
44		proto->d_ioctl = diskioctl;
45		proto->d_strategy = diskstrategy;
46		proto->d_psize = diskpsize;
47		cdevsw_add(proto);
48	}
49
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_flags = 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	dsgone(&disk->d_slice);
92}
93
94void
95disk_delete(dev_t dev)
96{
97	return;
98}
99
100/*
101 * The cdevsw functions
102 */
103
104static int
105diskopen(dev_t dev, int oflags, int devtype, struct proc *p)
106{
107	dev_t pdev;
108	struct disk *dp;
109	int error;
110
111	error = 0;
112	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
113
114	dp = pdev->si_disk;
115	if (!dp)
116		return (ENXIO);
117
118	if (!dsisopen(dp->d_slice)) {
119		if (!pdev->si_iosize_max)
120			pdev->si_iosize_max = dev->si_iosize_max;
121		error = dp->d_devsw->d_open(pdev, oflags, devtype, p);
122	}
123
124	/* Inherit properties from the whole/raw dev_t */
125	dev->si_disk = pdev->si_disk;
126	dev->si_drv1 = pdev->si_drv1;
127	dev->si_drv2 = pdev->si_drv2;
128	dev->si_iosize_max = pdev->si_iosize_max;
129	dev->si_bsize_phys = pdev->si_bsize_phys;
130	dev->si_bsize_best = pdev->si_bsize_best;
131
132	if (error)
133		return(error);
134
135	error = dsopen(dev, devtype, dp->d_flags, &dp->d_slice, &dp->d_label);
136
137	if (!dsisopen(dp->d_slice))
138		dp->d_devsw->d_close(dev, oflags, devtype, p);
139
140	return(error);
141}
142
143static int
144diskclose(dev_t dev, int fflag, int devtype, struct proc *p)
145{
146	struct disk *dp;
147	int error;
148	dev_t pdev;
149
150	error = 0;
151	dp = dev->si_disk;
152	dsclose(dev, devtype, dp->d_slice);
153	if (!dsisopen(dp->d_slice)) {
154		pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
155		error = dp->d_devsw->d_close(pdev, fflag, devtype, p);
156	}
157	return (error);
158}
159
160static void
161diskstrategy(struct buf *bp)
162{
163	dev_t pdev;
164	struct disk *dp;
165
166	dp = bp->b_dev->si_disk;
167	if (!dp) {
168		pdev = dkmodpart(dkmodslice(bp->b_dev, WHOLE_DISK_SLICE), RAW_PART);
169		dp = bp->b_dev->si_disk = pdev->si_disk;
170		bp->b_dev->si_drv1 = pdev->si_drv1;
171		bp->b_dev->si_drv2 = pdev->si_drv2;
172		bp->b_dev->si_iosize_max = pdev->si_iosize_max;
173		bp->b_dev->si_bsize_phys = pdev->si_bsize_phys;
174		bp->b_dev->si_bsize_best = pdev->si_bsize_best;
175	}
176
177	if (!dp) {
178		bp->b_error = ENXIO;
179		bp->b_flags |= B_ERROR;
180		biodone(bp);
181		return;
182	}
183
184	if (dscheck(bp, dp->d_slice) < 0) {
185		biodone(bp);
186		return;
187	}
188
189	dp->d_devsw->d_strategy(bp);
190	return;
191
192}
193
194static int
195diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
196{
197	struct disk *dp;
198	int error;
199
200	dp = dev->si_disk;
201	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
202	if (error == ENOIOCTL)
203		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p);
204	return (error);
205}
206
207static int
208diskpsize(dev_t dev)
209{
210	struct disk *dp;
211	dev_t pdev;
212
213	dp = dev->si_disk;
214	if (!dp) {
215		pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
216		dp = pdev->si_disk;
217		dev->si_drv1 = pdev->si_drv1;
218		dev->si_drv2 = pdev->si_drv2;
219		/* XXX: don't set bp->b_dev->si_disk (?) */
220	}
221	return (dssize(dev, &dp->d_slice));
222}
223
224SYSCTL_DECL(_debug_sizeof);
225
226SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
227    0, sizeof(struct disklabel), "sizeof(struct disklabel)");
228
229SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
230    0, sizeof(struct diskslices), "sizeof(struct diskslices)");
231
232SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
233    0, sizeof(struct disk), "sizeof(struct disk)");
234