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