xref: /freebsd/sys/kern/subr_disk.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
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/sysctl.h>
17 #include <sys/buf.h>
18 #include <sys/conf.h>
19 #include <sys/disk.h>
20 #include <sys/malloc.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 dev_t
32 disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
33 {
34 	dev_t dev;
35 
36 	bzero(dp, sizeof(*dp));
37 
38 	dev = makedev(cdevsw->d_maj, 0);
39 	if (!devsw(dev)) {
40 		*proto = *cdevsw;
41 		proto->d_open = diskopen;
42 		proto->d_close = diskclose;
43 		proto->d_ioctl = diskioctl;
44 		proto->d_strategy = diskstrategy;
45 		proto->d_psize = diskpsize;
46 		cdevsw_add(proto);
47 	}
48 
49 	if (bootverbose)
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_dsflags = flags;
57 	dp->d_devsw = cdevsw;
58 	return (dev);
59 }
60 
61 int
62 disk_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 
88 void
89 disk_invalidate (struct disk *disk)
90 {
91 	if (disk->d_slice)
92 		dsgone(&disk->d_slice);
93 }
94 
95 void
96 disk_destroy(dev_t dev)
97 {
98     	dev->si_disk = NULL;
99 	destroy_dev(dev);
100 	return;
101 }
102 
103 /*
104  * The cdevsw functions
105  */
106 
107 static int
108 diskopen(dev_t dev, int oflags, int devtype, struct proc *p)
109 {
110 	dev_t pdev;
111 	struct disk *dp;
112 	int error;
113 
114 	error = 0;
115 	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
116 
117 	dp = pdev->si_disk;
118 	if (!dp)
119 		return (ENXIO);
120 
121 	while (dp->d_flags & DISKFLAG_LOCK) {
122 		dp->d_flags |= DISKFLAG_WANTED;
123 		error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
124 		if (error)
125 			return (error);
126 	}
127 	dp->d_flags |= DISKFLAG_LOCK;
128 
129 	if (!dsisopen(dp->d_slice)) {
130 		if (!pdev->si_iosize_max)
131 			pdev->si_iosize_max = dev->si_iosize_max;
132 		error = dp->d_devsw->d_open(pdev, oflags, devtype, p);
133 	}
134 
135 	/* Inherit properties from the whole/raw dev_t */
136 	dev->si_disk = pdev->si_disk;
137 	dev->si_drv1 = pdev->si_drv1;
138 	dev->si_drv2 = pdev->si_drv2;
139 	dev->si_iosize_max = pdev->si_iosize_max;
140 	dev->si_bsize_phys = pdev->si_bsize_phys;
141 	dev->si_bsize_best = pdev->si_bsize_best;
142 
143 	if (error)
144 		goto out;
145 
146 	error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
147 
148 	if (!dsisopen(dp->d_slice))
149 		dp->d_devsw->d_close(pdev, oflags, devtype, p);
150 out:
151 	dp->d_flags &= ~DISKFLAG_LOCK;
152 	if (dp->d_flags & DISKFLAG_WANTED) {
153 		dp->d_flags &= ~DISKFLAG_WANTED;
154 		wakeup(dp);
155 	}
156 
157 	return(error);
158 }
159 
160 static int
161 diskclose(dev_t dev, int fflag, int devtype, struct proc *p)
162 {
163 	struct disk *dp;
164 	int error;
165 
166 	error = 0;
167 	dp = dev->si_disk;
168 	dsclose(dev, devtype, dp->d_slice);
169 	if (!dsisopen(dp->d_slice)) {
170 		error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p);
171 	}
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 = bp->b_dev->si_disk = pdev->si_disk;
185 		bp->b_dev->si_drv1 = pdev->si_drv1;
186 		bp->b_dev->si_drv2 = pdev->si_drv2;
187 		bp->b_dev->si_iosize_max = pdev->si_iosize_max;
188 		bp->b_dev->si_bsize_phys = pdev->si_bsize_phys;
189 		bp->b_dev->si_bsize_best = pdev->si_bsize_best;
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 
239 SYSCTL_DECL(_debug_sizeof);
240 
241 SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
242     0, sizeof(struct disklabel), "sizeof(struct disklabel)");
243 
244 SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
245     0, sizeof(struct diskslices), "sizeof(struct diskslices)");
246 
247 SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
248     0, sizeof(struct disk), "sizeof(struct disk)");
249