xref: /freebsd/sys/kern/subr_disk.c (revision f9ce010afdd3136fc73e2b500f2ed916bf9cfa59)
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$
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 
23 MALLOC_DEFINE(M_DISK, "disk", "disk data");
24 
25 static d_strategy_t diskstrategy;
26 static d_open_t diskopen;
27 static d_close_t diskclose;
28 static d_ioctl_t diskioctl;
29 static d_psize_t diskpsize;
30 
31 static 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 
53 dev_t
54 disk_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 
86 int
87 disk_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 
113 void
114 disk_invalidate (struct disk *disk)
115 {
116 	dsgone(&disk->d_slice);
117 }
118 
119 void
120 disk_delete(dev_t dev)
121 {
122 	return;
123 }
124 
125 /*
126  * The cdevsw functions
127  */
128 
129 static int
130 diskopen(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 
161 static int
162 diskclose(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 
175 static void
176 diskstrategy(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 
209 static int
210 diskioctl(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 
222 static int
223 diskpsize(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