xref: /freebsd/sys/kern/subr_disk.c (revision a14a0223ae1b172e96dd2a1d849e22026a98b692)
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 	printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
50 	dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
51 	    0, 0, 0, "r%s%d", cdevsw->d_name, unit);
52 
53 	dev->si_disk = dp;
54 	dp->d_dev = dev;
55 	dp->d_dsflags = flags;
56 	dp->d_devsw = cdevsw;
57 	return (dev);
58 }
59 
60 int
61 disk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
62 {
63 	struct disk *dp;
64 	struct disklabel *dl;
65 	u_int boff;
66 
67 	dp = dev->si_disk;
68 	if (!dp)
69 		return (ENXIO);
70 	if (!dp->d_slice)
71 		return (ENXIO);
72 	dl = dsgetlabel(dev, dp->d_slice);
73 	if (!dl)
74 		return (ENXIO);
75 	*count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize;
76 	if (dumplo < 0 ||
77 	    (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size))
78 		return (EINVAL);
79 	boff = dl->d_partitions[dkpart(dev)].p_offset +
80 	    dp->d_slice->dss_slices[dkslice(dev)].ds_offset;
81 	*blkno = boff + dumplo;
82 	*secsize = dl->d_secsize;
83 	return (0);
84 
85 }
86 
87 void
88 disk_invalidate (struct disk *disk)
89 {
90 	dsgone(&disk->d_slice);
91 }
92 
93 void
94 disk_delete(dev_t dev)
95 {
96 	return;
97 }
98 
99 /*
100  * The cdevsw functions
101  */
102 
103 static int
104 diskopen(dev_t dev, int oflags, int devtype, struct proc *p)
105 {
106 	dev_t pdev;
107 	struct disk *dp;
108 	int error;
109 
110 	error = 0;
111 	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
112 
113 	dp = pdev->si_disk;
114 	if (!dp)
115 		return (ENXIO);
116 
117 	while (dp->d_flags & DISKFLAG_LOCK) {
118 		dp->d_flags |= DISKFLAG_WANTED;
119 		tsleep(dp, PRIBIO | PCATCH, "diskopen", hz);
120 	}
121 	dp->d_flags |= DISKFLAG_LOCK;
122 
123 	if (!dsisopen(dp->d_slice)) {
124 		if (!pdev->si_iosize_max)
125 			pdev->si_iosize_max = dev->si_iosize_max;
126 		error = dp->d_devsw->d_open(pdev, oflags, devtype, p);
127 	}
128 
129 	/* Inherit properties from the whole/raw dev_t */
130 	dev->si_disk = pdev->si_disk;
131 	dev->si_drv1 = pdev->si_drv1;
132 	dev->si_drv2 = pdev->si_drv2;
133 	dev->si_iosize_max = pdev->si_iosize_max;
134 	dev->si_bsize_phys = pdev->si_bsize_phys;
135 	dev->si_bsize_best = pdev->si_bsize_best;
136 
137 	if (error)
138 		goto out;
139 
140 	error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label);
141 
142 	if (!dsisopen(dp->d_slice))
143 		dp->d_devsw->d_close(pdev, oflags, devtype, p);
144 out:
145 	dp->d_flags &= ~DISKFLAG_LOCK;
146 	if (dp->d_flags & DISKFLAG_WANTED) {
147 		dp->d_flags &= ~DISKFLAG_WANTED;
148 		wakeup(dp);
149 	}
150 
151 	return(error);
152 }
153 
154 static int
155 diskclose(dev_t dev, int fflag, int devtype, struct proc *p)
156 {
157 	struct disk *dp;
158 	int error;
159 
160 	error = 0;
161 	dp = dev->si_disk;
162 	dsclose(dev, devtype, dp->d_slice);
163 	if (!dsisopen(dp->d_slice)) {
164 		error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p);
165 	}
166 	return (error);
167 }
168 
169 static void
170 diskstrategy(struct buf *bp)
171 {
172 	dev_t pdev;
173 	struct disk *dp;
174 
175 	dp = bp->b_dev->si_disk;
176 	if (!dp) {
177 		pdev = dkmodpart(dkmodslice(bp->b_dev, WHOLE_DISK_SLICE), RAW_PART);
178 		dp = bp->b_dev->si_disk = pdev->si_disk;
179 		bp->b_dev->si_drv1 = pdev->si_drv1;
180 		bp->b_dev->si_drv2 = pdev->si_drv2;
181 		bp->b_dev->si_iosize_max = pdev->si_iosize_max;
182 		bp->b_dev->si_bsize_phys = pdev->si_bsize_phys;
183 		bp->b_dev->si_bsize_best = pdev->si_bsize_best;
184 	}
185 
186 	if (!dp) {
187 		bp->b_error = ENXIO;
188 		bp->b_flags |= B_ERROR;
189 		biodone(bp);
190 		return;
191 	}
192 
193 	if (dscheck(bp, dp->d_slice) < 0) {
194 		biodone(bp);
195 		return;
196 	}
197 
198 	dp->d_devsw->d_strategy(bp);
199 	return;
200 
201 }
202 
203 static int
204 diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
205 {
206 	struct disk *dp;
207 	int error;
208 
209 	dp = dev->si_disk;
210 	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
211 	if (error == ENOIOCTL)
212 		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p);
213 	return (error);
214 }
215 
216 static int
217 diskpsize(dev_t dev)
218 {
219 	struct disk *dp;
220 	dev_t pdev;
221 
222 	dp = dev->si_disk;
223 	if (!dp) {
224 		pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
225 		dp = pdev->si_disk;
226 		dev->si_drv1 = pdev->si_drv1;
227 		dev->si_drv2 = pdev->si_drv2;
228 		/* XXX: don't set bp->b_dev->si_disk (?) */
229 	}
230 	return (dssize(dev, &dp->d_slice));
231 }
232 
233 SYSCTL_DECL(_debug_sizeof);
234 
235 SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
236     0, sizeof(struct disklabel), "sizeof(struct disklabel)");
237 
238 SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
239     0, sizeof(struct diskslices), "sizeof(struct diskslices)");
240 
241 SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
242     0, sizeof(struct disk), "sizeof(struct disk)");
243