xref: /freebsd/sys/kern/subr_disk.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
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_flags = 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 	if (!dsisopen(dp->d_slice)) {
118 		if (!pdev->si_iosize_max)
119 			pdev->si_iosize_max = dev->si_iosize_max;
120 		error = dp->d_devsw->d_open(pdev, oflags, devtype, p);
121 	}
122 
123 	/* Inherit properties from the whole/raw dev_t */
124 	dev->si_disk = pdev->si_disk;
125 	dev->si_drv1 = pdev->si_drv1;
126 	dev->si_drv2 = pdev->si_drv2;
127 	dev->si_iosize_max = pdev->si_iosize_max;
128 	dev->si_bsize_phys = pdev->si_bsize_phys;
129 	dev->si_bsize_best = pdev->si_bsize_best;
130 
131 	if (error)
132 		return(error);
133 
134 	error = dsopen(dev, devtype, dp->d_flags, &dp->d_slice, &dp->d_label);
135 
136 	if (!dsisopen(dp->d_slice))
137 		dp->d_devsw->d_close(pdev, oflags, devtype, p);
138 
139 	return(error);
140 }
141 
142 static int
143 diskclose(dev_t dev, int fflag, int devtype, struct proc *p)
144 {
145 	struct disk *dp;
146 	int error;
147 
148 	error = 0;
149 	dp = dev->si_disk;
150 	dsclose(dev, devtype, dp->d_slice);
151 	if (!dsisopen(dp->d_slice)) {
152 		error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p);
153 	}
154 	return (error);
155 }
156 
157 static void
158 diskstrategy(struct buf *bp)
159 {
160 	dev_t pdev;
161 	struct disk *dp;
162 
163 	dp = bp->b_dev->si_disk;
164 	if (!dp) {
165 		pdev = dkmodpart(dkmodslice(bp->b_dev, WHOLE_DISK_SLICE), RAW_PART);
166 		dp = bp->b_dev->si_disk = pdev->si_disk;
167 		bp->b_dev->si_drv1 = pdev->si_drv1;
168 		bp->b_dev->si_drv2 = pdev->si_drv2;
169 		bp->b_dev->si_iosize_max = pdev->si_iosize_max;
170 		bp->b_dev->si_bsize_phys = pdev->si_bsize_phys;
171 		bp->b_dev->si_bsize_best = pdev->si_bsize_best;
172 	}
173 
174 	if (!dp) {
175 		bp->b_error = ENXIO;
176 		bp->b_flags |= B_ERROR;
177 		biodone(bp);
178 		return;
179 	}
180 
181 	if (dscheck(bp, dp->d_slice) < 0) {
182 		biodone(bp);
183 		return;
184 	}
185 
186 	dp->d_devsw->d_strategy(bp);
187 	return;
188 
189 }
190 
191 static int
192 diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
193 {
194 	struct disk *dp;
195 	int error;
196 
197 	dp = dev->si_disk;
198 	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
199 	if (error == ENOIOCTL)
200 		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p);
201 	return (error);
202 }
203 
204 static int
205 diskpsize(dev_t dev)
206 {
207 	struct disk *dp;
208 	dev_t pdev;
209 
210 	dp = dev->si_disk;
211 	if (!dp) {
212 		pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
213 		dp = pdev->si_disk;
214 		dev->si_drv1 = pdev->si_drv1;
215 		dev->si_drv2 = pdev->si_drv2;
216 		/* XXX: don't set bp->b_dev->si_disk (?) */
217 	}
218 	return (dssize(dev, &dp->d_slice));
219 }
220 
221 SYSCTL_DECL(_debug_sizeof);
222 
223 SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
224     0, sizeof(struct disklabel), "sizeof(struct disklabel)");
225 
226 SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
227     0, sizeof(struct diskslices), "sizeof(struct diskslices)");
228 
229 SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
230     0, sizeof(struct disk), "sizeof(struct disk)");
231