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 62454 2000-07-03 09:35:31Z 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/bio.h>
18#include <sys/conf.h>
19#include <sys/disk.h>
20#include <sys/malloc.h>
21#include <sys/sysctl.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
32static LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist);
33
34dev_t
35disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
36{
37 dev_t dev;
38
39 bzero(dp, sizeof(*dp));
40
41 dev = makedev(cdevsw->d_maj, 0);
42 if (!devsw(dev)) {
43 *proto = *cdevsw;
44 proto->d_open = diskopen;
45 proto->d_close = diskclose;
46 proto->d_ioctl = diskioctl;
47 proto->d_strategy = diskstrategy;
48 proto->d_psize = diskpsize;
49 cdevsw_add(proto);
50 }
51
52 if (bootverbose)
53 printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
54 dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
55 0, 0, 0, "%s%d", cdevsw->d_name, unit);
56
57 dev->si_disk = dp;
58 dp->d_dev = dev;
59 dp->d_dsflags = flags;
60 dp->d_devsw = cdevsw;
61 LIST_INSERT_HEAD(&disklist, dp, d_list);
62 return (dev);
63}
64
65int
66disk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
67{
68 struct disk *dp;
69 struct disklabel *dl;
70 u_int boff;
71
72 dp = dev->si_disk;
73 if (!dp)
74 return (ENXIO);
75 if (!dp->d_slice)
76 return (ENXIO);
77 dl = dsgetlabel(dev, dp->d_slice);
78 if (!dl)
79 return (ENXIO);
80 *count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize;
81 if (dumplo < 0 ||
82 (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
83 return (EINVAL);
84 boff = dl->d_partitions[dkpart(dev)].p_offset +
85 dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
86 *blkno = boff + dumplo;
87 *secsize = dl->d_secsize;
88 return (0);
89
90}
91
92void
93disk_invalidate (struct disk *disk)
94{
95 if (disk->d_slice)
96 dsgone(&disk->d_slice);
97}
98
99void
100disk_destroy(dev_t dev)
101{
102 LIST_REMOVE(dev->si_disk, d_list);
103 bzero(dev->si_disk, sizeof(*dev->si_disk));
104 dev->si_disk = NULL;
105 destroy_dev(dev);
106 return;
107}
108
109struct disk *
110disk_enumerate(struct disk *disk)
111{
112 if (!disk)
113 return (LIST_FIRST(&disklist));
114 else
115 return (LIST_NEXT(disk, d_list));
116}
117
118static int
119sysctl_disks (SYSCTL_HANDLER_ARGS)
120{
121 struct disk *disk;
122 int error, first;
123
124 disk = NULL;
125 first = 1;
126
127 while ((disk = disk_enumerate(disk))) {
128 if (!first) {
129 error = SYSCTL_OUT(req, " ", 1);
130 if (error)
131 return error;
132 } else {
133 first = 0;
134 }
135 error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name));
136 if (error)
137 return error;
138 }
139 error = SYSCTL_OUT(req, "", 1);
140 return error;
141}
142
143SYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL,
144 sysctl_disks, "A", "names of available disks");
145
146/*
147 * The cdevsw functions
148 */
149
150static int
151diskopen(dev_t dev, int oflags, int devtype, struct proc *p)
152{
153 dev_t pdev;
154 struct disk *dp;
155 int error;
156
157 error = 0;
158 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
159
160 dp = pdev->si_disk;
161 if (!dp)
162 return (ENXIO);
163
164 while (dp->d_flags & DISKFLAG_LOCK) {
165 dp->d_flags |= DISKFLAG_WANTED;
166 error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
167 if (error)
168 return (error);
169 }
170 dp->d_flags |= DISKFLAG_LOCK;
171
172 if (!dsisopen(dp->d_slice)) {
173 if (!pdev->si_iosize_max)
174 pdev->si_iosize_max = dev->si_iosize_max;
175 error = dp->d_devsw->d_open(pdev, oflags, devtype, p);
176 }
177
178 /* Inherit properties from the whole/raw dev_t */
179 dev->si_disk = pdev->si_disk;
180 dev->si_drv1 = pdev->si_drv1;
181 dev->si_drv2 = pdev->si_drv2;
182 dev->si_iosize_max = pdev->si_iosize_max;
183 dev->si_bsize_phys = pdev->si_bsize_phys;
184 dev->si_bsize_best = pdev->si_bsize_best;
185
186 if (error)
187 goto out;
188
189 error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
190
191 if (!dsisopen(dp->d_slice))
192 dp->d_devsw->d_close(pdev, oflags, devtype, p);
193out:
194 dp->d_flags &= ~DISKFLAG_LOCK;
195 if (dp->d_flags & DISKFLAG_WANTED) {
196 dp->d_flags &= ~DISKFLAG_WANTED;
197 wakeup(dp);
198 }
199
200 return(error);
201}
202
203static int
204diskclose(dev_t dev, int fflag, int devtype, struct proc *p)
205{
206 struct disk *dp;
207 int error;
208
209 error = 0;
210 dp = dev->si_disk;
211 dsclose(dev, devtype, dp->d_slice);
212 if (!dsisopen(dp->d_slice)) {
213 error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p);
214 }
215 return (error);
216}
217
218static void
219diskstrategy(struct bio *bp)
220{
221 dev_t pdev;
222 struct disk *dp;
223
224 dp = bp->bio_dev->si_disk;
225 if (!dp) {
226 pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
227 dp = bp->bio_dev->si_disk = pdev->si_disk;
228 bp->bio_dev->si_drv1 = pdev->si_drv1;
229 bp->bio_dev->si_drv2 = pdev->si_drv2;
230 bp->bio_dev->si_iosize_max = pdev->si_iosize_max;
231 bp->bio_dev->si_bsize_phys = pdev->si_bsize_phys;
232 bp->bio_dev->si_bsize_best = pdev->si_bsize_best;
233 }
234
235 if (!dp) {
236 bp->bio_error = ENXIO;
237 bp->bio_flags |= BIO_ERROR;
238 biodone(bp);
239 return;
240 }
241
242 if (dscheck(bp, dp->d_slice) <= 0) {
243 biodone(bp);
244 return;
245 }
246
247 KASSERT(dp->d_devsw != NULL, ("NULL devsw"));
248 KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy"));
249 dp->d_devsw->d_strategy(bp);
250 return;
251
252}
253
254static int
255diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
256{
257 struct disk *dp;
258 int error;
259
260 dp = dev->si_disk;
261 error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
262 if (error == ENOIOCTL)
263 error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p);
264 return (error);
265}
266
267static int
268diskpsize(dev_t dev)
269{
270 struct disk *dp;
271 dev_t pdev;
272
273 dp = dev->si_disk;
274 if (!dp) {
275 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
276 dp = pdev->si_disk;
277 if (!dp)
278 return (-1);
279 dev->si_drv1 = pdev->si_drv1;
280 dev->si_drv2 = pdev->si_drv2;
281 /* XXX: don't set bp->b_dev->si_disk (?) */
282 }
283 return (dssize(dev, &dp->d_slice));
284}
285
286SYSCTL_DECL(_debug_sizeof);
287
288SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
289 0, sizeof(struct disklabel), "sizeof(struct disklabel)");
290
291SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
292 0, sizeof(struct diskslices), "sizeof(struct diskslices)");
293
294SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
295 0, sizeof(struct disk), "sizeof(struct disk)");
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 62454 2000-07-03 09:35:31Z 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/bio.h>
18#include <sys/conf.h>
19#include <sys/disk.h>
20#include <sys/malloc.h>
21#include <sys/sysctl.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
32static LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist);
33
34dev_t
35disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
36{
37 dev_t dev;
38
39 bzero(dp, sizeof(*dp));
40
41 dev = makedev(cdevsw->d_maj, 0);
42 if (!devsw(dev)) {
43 *proto = *cdevsw;
44 proto->d_open = diskopen;
45 proto->d_close = diskclose;
46 proto->d_ioctl = diskioctl;
47 proto->d_strategy = diskstrategy;
48 proto->d_psize = diskpsize;
49 cdevsw_add(proto);
50 }
51
52 if (bootverbose)
53 printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
54 dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
55 0, 0, 0, "%s%d", cdevsw->d_name, unit);
56
57 dev->si_disk = dp;
58 dp->d_dev = dev;
59 dp->d_dsflags = flags;
60 dp->d_devsw = cdevsw;
61 LIST_INSERT_HEAD(&disklist, dp, d_list);
62 return (dev);
63}
64
65int
66disk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
67{
68 struct disk *dp;
69 struct disklabel *dl;
70 u_int boff;
71
72 dp = dev->si_disk;
73 if (!dp)
74 return (ENXIO);
75 if (!dp->d_slice)
76 return (ENXIO);
77 dl = dsgetlabel(dev, dp->d_slice);
78 if (!dl)
79 return (ENXIO);
80 *count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize;
81 if (dumplo < 0 ||
82 (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
83 return (EINVAL);
84 boff = dl->d_partitions[dkpart(dev)].p_offset +
85 dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
86 *blkno = boff + dumplo;
87 *secsize = dl->d_secsize;
88 return (0);
89
90}
91
92void
93disk_invalidate (struct disk *disk)
94{
95 if (disk->d_slice)
96 dsgone(&disk->d_slice);
97}
98
99void
100disk_destroy(dev_t dev)
101{
102 LIST_REMOVE(dev->si_disk, d_list);
103 bzero(dev->si_disk, sizeof(*dev->si_disk));
104 dev->si_disk = NULL;
105 destroy_dev(dev);
106 return;
107}
108
109struct disk *
110disk_enumerate(struct disk *disk)
111{
112 if (!disk)
113 return (LIST_FIRST(&disklist));
114 else
115 return (LIST_NEXT(disk, d_list));
116}
117
118static int
119sysctl_disks (SYSCTL_HANDLER_ARGS)
120{
121 struct disk *disk;
122 int error, first;
123
124 disk = NULL;
125 first = 1;
126
127 while ((disk = disk_enumerate(disk))) {
128 if (!first) {
129 error = SYSCTL_OUT(req, " ", 1);
130 if (error)
131 return error;
132 } else {
133 first = 0;
134 }
135 error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name));
136 if (error)
137 return error;
138 }
139 error = SYSCTL_OUT(req, "", 1);
140 return error;
141}
142
143SYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL,
144 sysctl_disks, "A", "names of available disks");
145
146/*
147 * The cdevsw functions
148 */
149
150static int
151diskopen(dev_t dev, int oflags, int devtype, struct proc *p)
152{
153 dev_t pdev;
154 struct disk *dp;
155 int error;
156
157 error = 0;
158 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
159
160 dp = pdev->si_disk;
161 if (!dp)
162 return (ENXIO);
163
164 while (dp->d_flags & DISKFLAG_LOCK) {
165 dp->d_flags |= DISKFLAG_WANTED;
166 error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
167 if (error)
168 return (error);
169 }
170 dp->d_flags |= DISKFLAG_LOCK;
171
172 if (!dsisopen(dp->d_slice)) {
173 if (!pdev->si_iosize_max)
174 pdev->si_iosize_max = dev->si_iosize_max;
175 error = dp->d_devsw->d_open(pdev, oflags, devtype, p);
176 }
177
178 /* Inherit properties from the whole/raw dev_t */
179 dev->si_disk = pdev->si_disk;
180 dev->si_drv1 = pdev->si_drv1;
181 dev->si_drv2 = pdev->si_drv2;
182 dev->si_iosize_max = pdev->si_iosize_max;
183 dev->si_bsize_phys = pdev->si_bsize_phys;
184 dev->si_bsize_best = pdev->si_bsize_best;
185
186 if (error)
187 goto out;
188
189 error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
190
191 if (!dsisopen(dp->d_slice))
192 dp->d_devsw->d_close(pdev, oflags, devtype, p);
193out:
194 dp->d_flags &= ~DISKFLAG_LOCK;
195 if (dp->d_flags & DISKFLAG_WANTED) {
196 dp->d_flags &= ~DISKFLAG_WANTED;
197 wakeup(dp);
198 }
199
200 return(error);
201}
202
203static int
204diskclose(dev_t dev, int fflag, int devtype, struct proc *p)
205{
206 struct disk *dp;
207 int error;
208
209 error = 0;
210 dp = dev->si_disk;
211 dsclose(dev, devtype, dp->d_slice);
212 if (!dsisopen(dp->d_slice)) {
213 error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p);
214 }
215 return (error);
216}
217
218static void
219diskstrategy(struct bio *bp)
220{
221 dev_t pdev;
222 struct disk *dp;
223
224 dp = bp->bio_dev->si_disk;
225 if (!dp) {
226 pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART);
227 dp = bp->bio_dev->si_disk = pdev->si_disk;
228 bp->bio_dev->si_drv1 = pdev->si_drv1;
229 bp->bio_dev->si_drv2 = pdev->si_drv2;
230 bp->bio_dev->si_iosize_max = pdev->si_iosize_max;
231 bp->bio_dev->si_bsize_phys = pdev->si_bsize_phys;
232 bp->bio_dev->si_bsize_best = pdev->si_bsize_best;
233 }
234
235 if (!dp) {
236 bp->bio_error = ENXIO;
237 bp->bio_flags |= BIO_ERROR;
238 biodone(bp);
239 return;
240 }
241
242 if (dscheck(bp, dp->d_slice) <= 0) {
243 biodone(bp);
244 return;
245 }
246
247 KASSERT(dp->d_devsw != NULL, ("NULL devsw"));
248 KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy"));
249 dp->d_devsw->d_strategy(bp);
250 return;
251
252}
253
254static int
255diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
256{
257 struct disk *dp;
258 int error;
259
260 dp = dev->si_disk;
261 error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
262 if (error == ENOIOCTL)
263 error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p);
264 return (error);
265}
266
267static int
268diskpsize(dev_t dev)
269{
270 struct disk *dp;
271 dev_t pdev;
272
273 dp = dev->si_disk;
274 if (!dp) {
275 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
276 dp = pdev->si_disk;
277 if (!dp)
278 return (-1);
279 dev->si_drv1 = pdev->si_drv1;
280 dev->si_drv2 = pdev->si_drv2;
281 /* XXX: don't set bp->b_dev->si_disk (?) */
282 }
283 return (dssize(dev, &dp->d_slice));
284}
285
286SYSCTL_DECL(_debug_sizeof);
287
288SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
289 0, sizeof(struct disklabel), "sizeof(struct disklabel)");
290
291SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
292 0, sizeof(struct diskslices), "sizeof(struct diskslices)");
293
294SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
295 0, sizeof(struct disk), "sizeof(struct disk)");