subr_disk.c revision 50728
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 50728 1999-09-01 05:38:09Z phk $
10 *
11 */
12
13#include <sys/param.h>
14#include <sys/systm.h>
15#include <sys/kernel.h>
16#include <sys/buf.h>
17#include <sys/conf.h>
18#include <sys/disk.h>
19#include <sys/malloc.h>
20#include <sys/vnode.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
31static struct cdevsw disk_cdevsw = {
32	/* open */      diskopen,
33	/* close */     diskclose,
34	/* read */      physread,
35	/* write */     physwrite,
36	/* ioctl */     diskioctl,
37	/* stop */      nostop,
38	/* reset */     noreset,
39	/* devtotty */  nodevtotty,
40	/* poll */      nopoll,
41	/* mmap */      nommap,
42	/* strategy */  diskstrategy,
43	/* name */      "disk",
44	/* parms */     noparms,
45	/* maj */       -1,
46	/* dump */      nodump,
47	/* psize */     diskpsize,
48	/* flags */     D_DISK,
49	/* maxio */     0,
50	/* bmaj */      -1,
51};
52
53dev_t
54disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw)
55{
56	dev_t dev;
57	struct cdevsw *cds;
58
59	dev = makedev(cdevsw->d_maj, 0);
60	cds = devsw(dev);
61	if (!cds) {
62		/* Build the "real" cdevsw */
63		MALLOC(cds, struct cdevsw *, sizeof(*cds), M_DISK, M_WAITOK);
64		*cds = disk_cdevsw;
65		cds->d_name = cdevsw->d_name;
66		cds->d_maj = cdevsw->d_maj;
67		cds->d_bmaj = cdevsw->d_bmaj;
68		cds->d_flags = cdevsw->d_flags & ~D_TRACKCLOSE;
69		cds->d_dump = cdevsw->d_dump;
70
71		cdevsw_add(cds);
72	}
73
74	printf("Creating DISK %s%d\n", cds->d_name, unit);
75	dev = make_dev(cds, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
76	    0, 0, 0, "r%s%d", cds->d_name, unit);
77
78	bzero(dp, sizeof(*dp));
79	dp->d_devsw = cdevsw;
80	dev->si_disk = dp;
81	dp->d_dev = dev;
82	dp->d_flags = flags;
83	return (dev);
84}
85
86int
87disk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
88{
89	struct disk *dp;
90	struct disklabel *dl;
91	u_int boff;
92
93	dp = dev->si_disk;
94	if (!dp)
95		return (ENXIO);
96	if (!dp->d_slice)
97		return (ENXIO);
98	dl = dsgetlabel(dev, dp->d_slice);
99	if (!dl)
100		return (ENXIO);
101	*count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize;
102	if (dumplo < 0 ||
103	    (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
104		return (EINVAL);
105	boff = dl->d_partitions[dkpart(dev)].p_offset +
106	    dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
107	*blkno = boff + dumplo;
108	*secsize = dl->d_secsize;
109	return (0);
110
111}
112
113void
114disk_invalidate (struct disk *disk)
115{
116	dsgone(&disk->d_slice);
117}
118
119void
120disk_delete(dev_t dev)
121{
122	return;
123}
124
125/*
126 * The cdevsw functions
127 */
128
129static int
130diskopen(dev_t dev, int oflags, int devtype, struct proc *p)
131{
132	dev_t pdev;
133	struct disk *dp;
134	int error;
135
136	error = 0;
137	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
138
139	dp = pdev->si_disk;
140	if (!dp)
141		return (ENXIO);
142
143	dev->si_disk = dp;
144	dev->si_drv1 = pdev->si_drv1;
145	dev->si_drv2 = pdev->si_drv2;
146
147	if (!dsisopen(dp->d_slice))
148		error = dp->d_devsw->d_open(dev, oflags, devtype, p);
149
150	if (error)
151		return(error);
152
153	error = dsopen(dev, devtype, dp->d_flags, &dp->d_slice, &dp->d_label);
154
155	if (!dsisopen(dp->d_slice))
156		dp->d_devsw->d_close(dev, oflags, devtype, p);
157
158	return(error);
159}
160
161static int
162diskclose(dev_t dev, int fflag, int devtype, struct proc *p)
163{
164	struct disk *dp;
165	int error;
166
167	error = 0;
168	dp = dev->si_disk;
169	dsclose(dev, devtype, dp->d_slice);
170	if (dsisopen(dp->d_slice))
171		error = dp->d_devsw->d_close(dev, fflag, devtype, p);
172	return (error);
173}
174
175static void
176diskstrategy(struct buf *bp)
177{
178	dev_t pdev;
179	struct disk *dp;
180
181	dp = bp->b_dev->si_disk;
182	if (!dp) {
183		pdev = dkmodpart(dkmodslice(bp->b_dev, WHOLE_DISK_SLICE), RAW_PART);
184		dp = pdev->si_disk;
185		bp->b_dev->si_drv1 = pdev->si_drv1;
186		bp->b_dev->si_drv2 = pdev->si_drv2;
187		/* XXX: don't set bp->b_dev->si_disk (?) */
188	} else {
189		pdev = dp->d_dev;
190	}
191
192	if (!dp) {
193		bp->b_error = ENXIO;
194		bp->b_flags |= B_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		dev->si_drv1 = pdev->si_drv1;
233		dev->si_drv2 = pdev->si_drv2;
234		/* XXX: don't set bp->b_dev->si_disk (?) */
235	}
236	return (dssize(dev, &dp->d_slice));
237}
238