xref: /freebsd/sys/kern/subr_disk.c (revision f35e5d0ef0a10ebda81a076bbd838d12b916dab5)
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 <sys/vnode.h>
22 #include <machine/md_var.h>
23 
24 MALLOC_DEFINE(M_DISK, "disk", "disk data");
25 
26 static d_strategy_t diskstrategy;
27 static d_open_t diskopen;
28 static d_close_t diskclose;
29 static d_ioctl_t diskioctl;
30 static d_psize_t diskpsize;
31 
32 dev_t
33 disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
34 {
35 	dev_t dev;
36 
37 	bzero(dp, sizeof(*dp));
38 
39 	dev = makedev(cdevsw->d_maj, 0);
40 	if (!devsw(dev)) {
41 		*proto = *cdevsw;
42 		proto->d_open = diskopen;
43 		proto->d_close = diskclose;
44 		proto->d_ioctl = diskioctl;
45 		proto->d_strategy = diskstrategy;
46 		proto->d_psize = diskpsize;
47 		cdevsw_add(proto);
48 	}
49 
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_flags = 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 	dsgone(&disk->d_slice);
92 }
93 
94 void
95 disk_delete(dev_t dev)
96 {
97 	return;
98 }
99 
100 /*
101  * The cdevsw functions
102  */
103 
104 static int
105 diskopen(dev_t dev, int oflags, int devtype, struct proc *p)
106 {
107 	dev_t pdev;
108 	struct disk *dp;
109 	int error;
110 
111 	error = 0;
112 	pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
113 
114 	dp = pdev->si_disk;
115 	if (!dp)
116 		return (ENXIO);
117 
118 	dev->si_disk = dp;
119 	dev->si_drv1 = pdev->si_drv1;
120 	dev->si_drv2 = pdev->si_drv2;
121 
122 	if (!dsisopen(dp->d_slice))
123 		error = dp->d_devsw->d_open(dev, oflags, devtype, p);
124 
125 	if (error)
126 		return(error);
127 
128 	error = dsopen(dev, devtype, dp->d_flags, &dp->d_slice, &dp->d_label);
129 
130 	if (!dsisopen(dp->d_slice))
131 		dp->d_devsw->d_close(dev, oflags, devtype, p);
132 
133 	return(error);
134 }
135 
136 static int
137 diskclose(dev_t dev, int fflag, int devtype, struct proc *p)
138 {
139 	struct disk *dp;
140 	int error;
141 
142 	error = 0;
143 	dp = dev->si_disk;
144 	dsclose(dev, devtype, dp->d_slice);
145 	if (dsisopen(dp->d_slice))
146 		error = dp->d_devsw->d_close(dev, fflag, devtype, p);
147 	return (error);
148 }
149 
150 static void
151 diskstrategy(struct buf *bp)
152 {
153 	dev_t pdev;
154 	struct disk *dp;
155 
156 	dp = bp->b_dev->si_disk;
157 	if (!dp) {
158 		pdev = dkmodpart(dkmodslice(bp->b_dev, WHOLE_DISK_SLICE), RAW_PART);
159 		dp = pdev->si_disk;
160 		bp->b_dev->si_drv1 = pdev->si_drv1;
161 		bp->b_dev->si_drv2 = pdev->si_drv2;
162 		/* XXX: don't set bp->b_dev->si_disk (?) */
163 	} else {
164 		pdev = dp->d_dev;
165 	}
166 
167 	if (!dp) {
168 		bp->b_error = ENXIO;
169 		bp->b_flags |= B_ERROR;
170 		biodone(bp);
171 		return;
172 	}
173 
174 	if (dscheck(bp, dp->d_slice) < 0) {
175 		biodone(bp);
176 		return;
177 	}
178 
179 	dp->d_devsw->d_strategy(bp);
180 	return;
181 
182 }
183 
184 static int
185 diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
186 {
187 	struct disk *dp;
188 	int error;
189 
190 	dp = dev->si_disk;
191 	error = dsioctl(dev, cmd, data, fflag, &dp->d_slice);
192 	if (error == ENOIOCTL)
193 		error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p);
194 	return (error);
195 }
196 
197 static int
198 diskpsize(dev_t dev)
199 {
200 	struct disk *dp;
201 	dev_t pdev;
202 
203 	dp = dev->si_disk;
204 	if (!dp) {
205 		pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
206 		dp = pdev->si_disk;
207 		dev->si_drv1 = pdev->si_drv1;
208 		dev->si_drv2 = pdev->si_drv2;
209 		/* XXX: don't set bp->b_dev->si_disk (?) */
210 	}
211 	return (dssize(dev, &dp->d_slice));
212 }
213 
214 SYSCTL_DECL(_debug_sizeof);
215 
216 SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
217     0, sizeof(struct disklabel), "sizeof(struct disklabel)");
218 
219 SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
220     0, sizeof(struct diskslices), "sizeof(struct diskslices)");
221 
222 SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
223     0, sizeof(struct disk), "sizeof(struct disk)");
224