| @@ -1,922 +1,934 @@ | | | @@ -1,922 +1,934 @@ |
1 | /* $NetBSD: ld.c,v 1.65 2009/05/07 09:11:42 cegger Exp $ */ | | 1 | /* $NetBSD: ld.c,v 1.66 2009/07/23 21:38:33 dyoung Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Andrew Doran and Charles M. Hannum. | | 8 | * by Andrew Doran and Charles M. Hannum. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Disk driver for use by RAID controllers. | | 33 | * Disk driver for use by RAID controllers. |
34 | */ | | 34 | */ |
35 | | | 35 | |
36 | #include <sys/cdefs.h> | | 36 | #include <sys/cdefs.h> |
37 | __KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.65 2009/05/07 09:11:42 cegger Exp $"); | | 37 | __KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.66 2009/07/23 21:38:33 dyoung Exp $"); |
38 | | | 38 | |
39 | #include "rnd.h" | | 39 | #include "rnd.h" |
40 | | | 40 | |
41 | #include <sys/param.h> | | 41 | #include <sys/param.h> |
42 | #include <sys/systm.h> | | 42 | #include <sys/systm.h> |
43 | #include <sys/kernel.h> | | 43 | #include <sys/kernel.h> |
44 | #include <sys/device.h> | | 44 | #include <sys/device.h> |
45 | #include <sys/queue.h> | | 45 | #include <sys/queue.h> |
46 | #include <sys/proc.h> | | 46 | #include <sys/proc.h> |
47 | #include <sys/buf.h> | | 47 | #include <sys/buf.h> |
48 | #include <sys/bufq.h> | | 48 | #include <sys/bufq.h> |
49 | #include <sys/endian.h> | | 49 | #include <sys/endian.h> |
50 | #include <sys/disklabel.h> | | 50 | #include <sys/disklabel.h> |
51 | #include <sys/disk.h> | | 51 | #include <sys/disk.h> |
52 | #include <sys/dkio.h> | | 52 | #include <sys/dkio.h> |
53 | #include <sys/stat.h> | | 53 | #include <sys/stat.h> |
54 | #include <sys/conf.h> | | 54 | #include <sys/conf.h> |
55 | #include <sys/fcntl.h> | | 55 | #include <sys/fcntl.h> |
56 | #include <sys/vnode.h> | | 56 | #include <sys/vnode.h> |
57 | #include <sys/syslog.h> | | 57 | #include <sys/syslog.h> |
58 | #include <sys/mutex.h> | | 58 | #include <sys/mutex.h> |
59 | #if NRND > 0 | | 59 | #if NRND > 0 |
60 | #include <sys/rnd.h> | | 60 | #include <sys/rnd.h> |
61 | #endif | | 61 | #endif |
62 | | | 62 | |
63 | #include <dev/ldvar.h> | | 63 | #include <dev/ldvar.h> |
64 | | | 64 | |
65 | #include <prop/proplib.h> | | 65 | #include <prop/proplib.h> |
66 | | | 66 | |
67 | static void ldgetdefaultlabel(struct ld_softc *, struct disklabel *); | | 67 | static void ldgetdefaultlabel(struct ld_softc *, struct disklabel *); |
68 | static void ldgetdisklabel(struct ld_softc *); | | 68 | static void ldgetdisklabel(struct ld_softc *); |
69 | static void ldminphys(struct buf *bp); | | 69 | static void ldminphys(struct buf *bp); |
70 | static bool ld_shutdown(device_t, int); | | 70 | static bool ld_shutdown(device_t, int); |
71 | static void ldstart(struct ld_softc *, struct buf *); | | 71 | static void ldstart(struct ld_softc *, struct buf *); |
72 | static void ld_set_properties(struct ld_softc *); | | 72 | static void ld_set_properties(struct ld_softc *); |
73 | static void ld_config_interrupts (device_t); | | 73 | static void ld_config_interrupts (device_t); |
| | | 74 | static int ldlastclose(device_t); |
74 | | | 75 | |
75 | extern struct cfdriver ld_cd; | | 76 | extern struct cfdriver ld_cd; |
76 | | | 77 | |
77 | static dev_type_open(ldopen); | | 78 | static dev_type_open(ldopen); |
78 | static dev_type_close(ldclose); | | 79 | static dev_type_close(ldclose); |
79 | static dev_type_read(ldread); | | 80 | static dev_type_read(ldread); |
80 | static dev_type_write(ldwrite); | | 81 | static dev_type_write(ldwrite); |
81 | static dev_type_ioctl(ldioctl); | | 82 | static dev_type_ioctl(ldioctl); |
82 | static dev_type_strategy(ldstrategy); | | 83 | static dev_type_strategy(ldstrategy); |
83 | static dev_type_dump(lddump); | | 84 | static dev_type_dump(lddump); |
84 | static dev_type_size(ldsize); | | 85 | static dev_type_size(ldsize); |
85 | | | 86 | |
86 | const struct bdevsw ld_bdevsw = { | | 87 | const struct bdevsw ld_bdevsw = { |
87 | ldopen, ldclose, ldstrategy, ldioctl, lddump, ldsize, D_DISK | | 88 | ldopen, ldclose, ldstrategy, ldioctl, lddump, ldsize, D_DISK |
88 | }; | | 89 | }; |
89 | | | 90 | |
90 | const struct cdevsw ld_cdevsw = { | | 91 | const struct cdevsw ld_cdevsw = { |
91 | ldopen, ldclose, ldread, ldwrite, ldioctl, | | 92 | ldopen, ldclose, ldread, ldwrite, ldioctl, |
92 | nostop, notty, nopoll, nommap, nokqfilter, D_DISK | | 93 | nostop, notty, nopoll, nommap, nokqfilter, D_DISK |
93 | }; | | 94 | }; |
94 | | | 95 | |
95 | static struct dkdriver lddkdriver = { ldstrategy, ldminphys }; | | 96 | static struct dkdriver lddkdriver = { ldstrategy, ldminphys }; |
96 | | | 97 | |
97 | void | | 98 | void |
98 | ldattach(struct ld_softc *sc) | | 99 | ldattach(struct ld_softc *sc) |
99 | { | | 100 | { |
100 | char tbuf[9]; | | 101 | char tbuf[9]; |
101 | | | 102 | |
102 | mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM); | | 103 | mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM); |
103 | | | 104 | |
104 | if ((sc->sc_flags & LDF_ENABLED) == 0) { | | 105 | if ((sc->sc_flags & LDF_ENABLED) == 0) { |
105 | aprint_normal_dev(sc->sc_dv, "disabled\n"); | | 106 | aprint_normal_dev(sc->sc_dv, "disabled\n"); |
106 | return; | | 107 | return; |
107 | } | | 108 | } |
108 | | | 109 | |
109 | /* Initialise and attach the disk structure. */ | | 110 | /* Initialise and attach the disk structure. */ |
110 | disk_init(&sc->sc_dk, device_xname(sc->sc_dv), &lddkdriver); | | 111 | disk_init(&sc->sc_dk, device_xname(sc->sc_dv), &lddkdriver); |
111 | disk_attach(&sc->sc_dk); | | 112 | disk_attach(&sc->sc_dk); |
112 | | | 113 | |
113 | if (sc->sc_maxxfer > MAXPHYS) | | 114 | if (sc->sc_maxxfer > MAXPHYS) |
114 | sc->sc_maxxfer = MAXPHYS; | | 115 | sc->sc_maxxfer = MAXPHYS; |
115 | | | 116 | |
116 | /* Build synthetic geometry if necessary. */ | | 117 | /* Build synthetic geometry if necessary. */ |
117 | if (sc->sc_nheads == 0 || sc->sc_nsectors == 0 || | | 118 | if (sc->sc_nheads == 0 || sc->sc_nsectors == 0 || |
118 | sc->sc_ncylinders == 0) { | | 119 | sc->sc_ncylinders == 0) { |
119 | uint64_t ncyl; | | 120 | uint64_t ncyl; |
120 | | | 121 | |
121 | if (sc->sc_secperunit <= 528 * 2048) /* 528MB */ | | 122 | if (sc->sc_secperunit <= 528 * 2048) /* 528MB */ |
122 | sc->sc_nheads = 16; | | 123 | sc->sc_nheads = 16; |
123 | else if (sc->sc_secperunit <= 1024 * 2048) /* 1GB */ | | 124 | else if (sc->sc_secperunit <= 1024 * 2048) /* 1GB */ |
124 | sc->sc_nheads = 32; | | 125 | sc->sc_nheads = 32; |
125 | else if (sc->sc_secperunit <= 21504 * 2048) /* 21GB */ | | 126 | else if (sc->sc_secperunit <= 21504 * 2048) /* 21GB */ |
126 | sc->sc_nheads = 64; | | 127 | sc->sc_nheads = 64; |
127 | else if (sc->sc_secperunit <= 43008 * 2048) /* 42GB */ | | 128 | else if (sc->sc_secperunit <= 43008 * 2048) /* 42GB */ |
128 | sc->sc_nheads = 128; | | 129 | sc->sc_nheads = 128; |
129 | else | | 130 | else |
130 | sc->sc_nheads = 255; | | 131 | sc->sc_nheads = 255; |
131 | | | 132 | |
132 | sc->sc_nsectors = 63; | | 133 | sc->sc_nsectors = 63; |
133 | sc->sc_ncylinders = INT_MAX; | | 134 | sc->sc_ncylinders = INT_MAX; |
134 | ncyl = sc->sc_secperunit / | | 135 | ncyl = sc->sc_secperunit / |
135 | (sc->sc_nheads * sc->sc_nsectors); | | 136 | (sc->sc_nheads * sc->sc_nsectors); |
136 | if (ncyl < INT_MAX) | | 137 | if (ncyl < INT_MAX) |
137 | sc->sc_ncylinders = (int)ncyl; | | 138 | sc->sc_ncylinders = (int)ncyl; |
138 | } | | 139 | } |
139 | | | 140 | |
140 | format_bytes(tbuf, sizeof(tbuf), sc->sc_secperunit * | | 141 | format_bytes(tbuf, sizeof(tbuf), sc->sc_secperunit * |
141 | sc->sc_secsize); | | 142 | sc->sc_secsize); |
142 | aprint_normal_dev(sc->sc_dv, "%s, %d cyl, %d head, %d sec, " | | 143 | aprint_normal_dev(sc->sc_dv, "%s, %d cyl, %d head, %d sec, " |
143 | "%d bytes/sect x %"PRIu64" sectors\n", | | 144 | "%d bytes/sect x %"PRIu64" sectors\n", |
144 | tbuf, sc->sc_ncylinders, sc->sc_nheads, | | 145 | tbuf, sc->sc_ncylinders, sc->sc_nheads, |
145 | sc->sc_nsectors, sc->sc_secsize, sc->sc_secperunit); | | 146 | sc->sc_nsectors, sc->sc_secsize, sc->sc_secperunit); |
146 | | | 147 | |
147 | ld_set_properties(sc); | | 148 | ld_set_properties(sc); |
148 | | | 149 | |
149 | #if NRND > 0 | | 150 | #if NRND > 0 |
150 | /* Attach the device into the rnd source list. */ | | 151 | /* Attach the device into the rnd source list. */ |
151 | rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dv), | | 152 | rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dv), |
152 | RND_TYPE_DISK, 0); | | 153 | RND_TYPE_DISK, 0); |
153 | #endif | | 154 | #endif |
154 | | | 155 | |
155 | /* Register with PMF */ | | 156 | /* Register with PMF */ |
156 | if (!pmf_device_register1(sc->sc_dv, NULL, NULL, ld_shutdown)) | | 157 | if (!pmf_device_register1(sc->sc_dv, NULL, NULL, ld_shutdown)) |
157 | aprint_error_dev(sc->sc_dv, | | 158 | aprint_error_dev(sc->sc_dv, |
158 | "couldn't establish power handler\n"); | | 159 | "couldn't establish power handler\n"); |
159 | | | 160 | |
160 | bufq_alloc(&sc->sc_bufq, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK); | | 161 | bufq_alloc(&sc->sc_bufq, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK); |
161 | | | 162 | |
162 | /* Discover wedges on this disk. */ | | 163 | /* Discover wedges on this disk. */ |
163 | config_interrupts(sc->sc_dv, ld_config_interrupts); | | 164 | config_interrupts(sc->sc_dv, ld_config_interrupts); |
164 | } | | 165 | } |
165 | | | 166 | |
166 | int | | 167 | int |
167 | ldadjqparam(struct ld_softc *sc, int xmax) | | 168 | ldadjqparam(struct ld_softc *sc, int xmax) |
168 | { | | 169 | { |
169 | int s; | | 170 | int s; |
170 | | | 171 | |
171 | s = splbio(); | | 172 | s = splbio(); |
172 | sc->sc_maxqueuecnt = xmax; | | 173 | sc->sc_maxqueuecnt = xmax; |
173 | splx(s); | | 174 | splx(s); |
174 | | | 175 | |
175 | return (0); | | 176 | return (0); |
176 | } | | 177 | } |
177 | | | 178 | |
178 | int | | 179 | int |
179 | ldbegindetach(struct ld_softc *sc, int flags) | | 180 | ldbegindetach(struct ld_softc *sc, int flags) |
180 | { | | 181 | { |
181 | int s, rv = 0; | | 182 | int s, rv = 0; |
182 | | | 183 | |
183 | if ((sc->sc_flags & LDF_ENABLED) == 0) | | 184 | if ((sc->sc_flags & LDF_ENABLED) == 0) |
184 | return (0); | | 185 | return (0); |
185 | | | 186 | |
186 | if ((flags & DETACH_FORCE) == 0 && sc->sc_dk.dk_openmask != 0) | | 187 | rv = disk_begindetach(&sc->sc_dk, ldlastclose, sc->sc_dv, flags); |
187 | return (EBUSY); | | 188 | |
| | | 189 | if (rv != 0) |
| | | 190 | return rv; |
188 | | | 191 | |
189 | s = splbio(); | | 192 | s = splbio(); |
190 | sc->sc_maxqueuecnt = 0; | | 193 | sc->sc_maxqueuecnt = 0; |
191 | sc->sc_flags |= LDF_DETACH; | | 194 | sc->sc_flags |= LDF_DETACH; |
192 | while (sc->sc_queuecnt > 0) { | | 195 | while (sc->sc_queuecnt > 0) { |
193 | sc->sc_flags |= LDF_DRAIN; | | 196 | sc->sc_flags |= LDF_DRAIN; |
194 | rv = tsleep(&sc->sc_queuecnt, PRIBIO, "lddrn", 0); | | 197 | rv = tsleep(&sc->sc_queuecnt, PRIBIO, "lddrn", 0); |
195 | if (rv) | | 198 | if (rv) |
196 | break; | | 199 | break; |
197 | } | | 200 | } |
198 | splx(s); | | 201 | splx(s); |
199 | | | 202 | |
200 | return (rv); | | 203 | return (rv); |
201 | } | | 204 | } |
202 | | | 205 | |
203 | void | | 206 | void |
204 | ldenddetach(struct ld_softc *sc) | | 207 | ldenddetach(struct ld_softc *sc) |
205 | { | | 208 | { |
206 | int s, bmaj, cmaj, i, mn; | | 209 | int s, bmaj, cmaj, i, mn; |
207 | | | 210 | |
208 | if ((sc->sc_flags & LDF_ENABLED) == 0) | | 211 | if ((sc->sc_flags & LDF_ENABLED) == 0) |
209 | return; | | 212 | return; |
210 | | | 213 | |
211 | /* Wait for commands queued with the hardware to complete. */ | | 214 | /* Wait for commands queued with the hardware to complete. */ |
212 | if (sc->sc_queuecnt != 0) | | 215 | if (sc->sc_queuecnt != 0) |
213 | if (tsleep(&sc->sc_queuecnt, PRIBIO, "lddtch", 30 * hz)) | | 216 | if (tsleep(&sc->sc_queuecnt, PRIBIO, "lddtch", 30 * hz)) |
214 | printf("%s: not drained\n", device_xname(sc->sc_dv)); | | 217 | printf("%s: not drained\n", device_xname(sc->sc_dv)); |
215 | | | 218 | |
216 | /* Locate the major numbers. */ | | 219 | /* Locate the major numbers. */ |
217 | bmaj = bdevsw_lookup_major(&ld_bdevsw); | | 220 | bmaj = bdevsw_lookup_major(&ld_bdevsw); |
218 | cmaj = cdevsw_lookup_major(&ld_cdevsw); | | 221 | cmaj = cdevsw_lookup_major(&ld_cdevsw); |
219 | | | 222 | |
220 | /* Kill off any queued buffers. */ | | 223 | /* Kill off any queued buffers. */ |
221 | s = splbio(); | | 224 | s = splbio(); |
222 | bufq_drain(sc->sc_bufq); | | 225 | bufq_drain(sc->sc_bufq); |
223 | splx(s); | | 226 | splx(s); |
224 | | | 227 | |
225 | bufq_free(sc->sc_bufq); | | 228 | bufq_free(sc->sc_bufq); |
226 | | | 229 | |
227 | /* Nuke the vnodes for any open instances. */ | | 230 | /* Nuke the vnodes for any open instances. */ |
228 | for (i = 0; i < MAXPARTITIONS; i++) { | | 231 | for (i = 0; i < MAXPARTITIONS; i++) { |
229 | mn = DISKMINOR(device_unit(sc->sc_dv), i); | | 232 | mn = DISKMINOR(device_unit(sc->sc_dv), i); |
230 | vdevgone(bmaj, mn, mn, VBLK); | | 233 | vdevgone(bmaj, mn, mn, VBLK); |
231 | vdevgone(cmaj, mn, mn, VCHR); | | 234 | vdevgone(cmaj, mn, mn, VCHR); |
232 | } | | 235 | } |
233 | | | 236 | |
234 | /* Delete all of our wedges. */ | | 237 | /* Delete all of our wedges. */ |
235 | dkwedge_delall(&sc->sc_dk); | | 238 | dkwedge_delall(&sc->sc_dk); |
236 | | | 239 | |
237 | /* Detach from the disk list. */ | | 240 | /* Detach from the disk list. */ |
238 | disk_detach(&sc->sc_dk); | | 241 | disk_detach(&sc->sc_dk); |
239 | disk_destroy(&sc->sc_dk); | | 242 | disk_destroy(&sc->sc_dk); |
240 | | | 243 | |
241 | #if NRND > 0 | | 244 | #if NRND > 0 |
242 | /* Unhook the entropy source. */ | | 245 | /* Unhook the entropy source. */ |
243 | rnd_detach_source(&sc->sc_rnd_source); | | 246 | rnd_detach_source(&sc->sc_rnd_source); |
244 | #endif | | 247 | #endif |
245 | | | 248 | |
246 | /* Deregister with PMF */ | | 249 | /* Deregister with PMF */ |
247 | pmf_device_deregister(sc->sc_dv); | | 250 | pmf_device_deregister(sc->sc_dv); |
248 | | | 251 | |
249 | /* | | 252 | /* |
250 | * XXX We can't really flush the cache here, beceause the | | 253 | * XXX We can't really flush the cache here, beceause the |
251 | * XXX device may already be non-existent from the controller's | | 254 | * XXX device may already be non-existent from the controller's |
252 | * XXX perspective. | | 255 | * XXX perspective. |
253 | */ | | 256 | */ |
254 | #if 0 | | 257 | #if 0 |
255 | /* Flush the device's cache. */ | | 258 | /* Flush the device's cache. */ |
256 | if (sc->sc_flush != NULL) | | 259 | if (sc->sc_flush != NULL) |
257 | if ((*sc->sc_flush)(sc, 0) != 0) | | 260 | if ((*sc->sc_flush)(sc, 0) != 0) |
258 | aprint_error_dev(&sc->sc_dv, "unable to flush cache\n"); | | 261 | aprint_error_dev(&sc->sc_dv, "unable to flush cache\n"); |
259 | #endif | | 262 | #endif |
260 | mutex_destroy(&sc->sc_mutex); | | 263 | mutex_destroy(&sc->sc_mutex); |
261 | } | | 264 | } |
262 | | | 265 | |
263 | /* ARGSUSED */ | | 266 | /* ARGSUSED */ |
264 | static bool | | 267 | static bool |
265 | ld_shutdown(device_t dev, int flags) | | 268 | ld_shutdown(device_t dev, int flags) |
266 | { | | 269 | { |
267 | struct ld_softc *sc = device_private(dev); | | 270 | struct ld_softc *sc = device_private(dev); |
268 | | | 271 | |
269 | if (sc->sc_flush != NULL && (*sc->sc_flush)(sc, LDFL_POLL) != 0) { | | 272 | if (sc->sc_flush != NULL && (*sc->sc_flush)(sc, LDFL_POLL) != 0) { |
270 | printf("%s: unable to flush cache\n", device_xname(dev)); | | 273 | printf("%s: unable to flush cache\n", device_xname(dev)); |
271 | return false; | | 274 | return false; |
272 | } | | 275 | } |
273 | | | 276 | |
274 | return true; | | 277 | return true; |
275 | } | | 278 | } |
276 | | | 279 | |
277 | /* ARGSUSED */ | | 280 | /* ARGSUSED */ |
278 | static int | | 281 | static int |
279 | ldopen(dev_t dev, int flags, int fmt, struct lwp *l) | | 282 | ldopen(dev_t dev, int flags, int fmt, struct lwp *l) |
280 | { | | 283 | { |
281 | struct ld_softc *sc; | | 284 | struct ld_softc *sc; |
282 | int error, unit, part; | | 285 | int error, unit, part; |
283 | | | 286 | |
284 | unit = DISKUNIT(dev); | | 287 | unit = DISKUNIT(dev); |
285 | if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) | | 288 | if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) |
286 | return (ENXIO); | | 289 | return (ENXIO); |
287 | if ((sc->sc_flags & LDF_ENABLED) == 0) | | 290 | if ((sc->sc_flags & LDF_ENABLED) == 0) |
288 | return (ENODEV); | | 291 | return (ENODEV); |
289 | part = DISKPART(dev); | | 292 | part = DISKPART(dev); |
290 | | | 293 | |
291 | mutex_enter(&sc->sc_dk.dk_openlock); | | 294 | mutex_enter(&sc->sc_dk.dk_openlock); |
292 | | | 295 | |
293 | if (sc->sc_dk.dk_openmask == 0) { | | 296 | if (sc->sc_dk.dk_openmask == 0) { |
294 | /* Load the partition info if not already loaded. */ | | 297 | /* Load the partition info if not already loaded. */ |
295 | if ((sc->sc_flags & LDF_VLABEL) == 0) | | 298 | if ((sc->sc_flags & LDF_VLABEL) == 0) |
296 | ldgetdisklabel(sc); | | 299 | ldgetdisklabel(sc); |
297 | } | | 300 | } |
298 | | | 301 | |
299 | /* Check that the partition exists. */ | | 302 | /* Check that the partition exists. */ |
300 | if (part != RAW_PART && (part >= sc->sc_dk.dk_label->d_npartitions || | | 303 | if (part != RAW_PART && (part >= sc->sc_dk.dk_label->d_npartitions || |
301 | sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { | | 304 | sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { |
302 | error = ENXIO; | | 305 | error = ENXIO; |
303 | goto bad1; | | 306 | goto bad1; |
304 | } | | 307 | } |
305 | | | 308 | |
306 | /* Ensure only one open at a time. */ | | 309 | /* Ensure only one open at a time. */ |
307 | switch (fmt) { | | 310 | switch (fmt) { |
308 | case S_IFCHR: | | 311 | case S_IFCHR: |
309 | sc->sc_dk.dk_copenmask |= (1 << part); | | 312 | sc->sc_dk.dk_copenmask |= (1 << part); |
310 | break; | | 313 | break; |
311 | case S_IFBLK: | | 314 | case S_IFBLK: |
312 | sc->sc_dk.dk_bopenmask |= (1 << part); | | 315 | sc->sc_dk.dk_bopenmask |= (1 << part); |
313 | break; | | 316 | break; |
314 | } | | 317 | } |
315 | sc->sc_dk.dk_openmask = | | 318 | sc->sc_dk.dk_openmask = |
316 | sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; | | 319 | sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; |
317 | | | 320 | |
318 | error = 0; | | 321 | error = 0; |
319 | bad1: | | 322 | bad1: |
320 | mutex_exit(&sc->sc_dk.dk_openlock); | | 323 | mutex_exit(&sc->sc_dk.dk_openlock); |
321 | return (error); | | 324 | return (error); |
322 | } | | 325 | } |
323 | | | 326 | |
| | | 327 | static int |
| | | 328 | ldlastclose(device_t self) |
| | | 329 | { |
| | | 330 | struct ld_softc *sc = device_private(self); |
| | | 331 | |
| | | 332 | if (sc->sc_flush != NULL && (*sc->sc_flush)(sc, 0) != 0) |
| | | 333 | aprint_error_dev(self, "unable to flush cache\n"); |
| | | 334 | if ((sc->sc_flags & LDF_KLABEL) == 0) |
| | | 335 | sc->sc_flags &= ~LDF_VLABEL; |
| | | 336 | |
| | | 337 | return 0; |
| | | 338 | } |
| | | 339 | |
324 | /* ARGSUSED */ | | 340 | /* ARGSUSED */ |
325 | static int | | 341 | static int |
326 | ldclose(dev_t dev, int flags, int fmt, struct lwp *l) | | 342 | ldclose(dev_t dev, int flags, int fmt, struct lwp *l) |
327 | { | | 343 | { |
328 | struct ld_softc *sc; | | 344 | struct ld_softc *sc; |
329 | int part, unit; | | 345 | int part, unit; |
330 | | | 346 | |
331 | unit = DISKUNIT(dev); | | 347 | unit = DISKUNIT(dev); |
332 | part = DISKPART(dev); | | 348 | part = DISKPART(dev); |
333 | sc = device_lookup_private(&ld_cd, unit); | | 349 | sc = device_lookup_private(&ld_cd, unit); |
334 | | | 350 | |
335 | mutex_enter(&sc->sc_dk.dk_openlock); | | 351 | mutex_enter(&sc->sc_dk.dk_openlock); |
336 | | | 352 | |
337 | switch (fmt) { | | 353 | switch (fmt) { |
338 | case S_IFCHR: | | 354 | case S_IFCHR: |
339 | sc->sc_dk.dk_copenmask &= ~(1 << part); | | 355 | sc->sc_dk.dk_copenmask &= ~(1 << part); |
340 | break; | | 356 | break; |
341 | case S_IFBLK: | | 357 | case S_IFBLK: |
342 | sc->sc_dk.dk_bopenmask &= ~(1 << part); | | 358 | sc->sc_dk.dk_bopenmask &= ~(1 << part); |
343 | break; | | 359 | break; |
344 | } | | 360 | } |
345 | sc->sc_dk.dk_openmask = | | 361 | sc->sc_dk.dk_openmask = |
346 | sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; | | 362 | sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; |
347 | | | 363 | |
348 | if (sc->sc_dk.dk_openmask == 0) { | | 364 | if (sc->sc_dk.dk_openmask == 0) |
349 | if (sc->sc_flush != NULL && (*sc->sc_flush)(sc, 0) != 0) | | 365 | ldlastclose(sc->sc_dv); |
350 | aprint_error_dev(sc->sc_dv, "unable to flush cache\n"); | | | |
351 | if ((sc->sc_flags & LDF_KLABEL) == 0) | | | |
352 | sc->sc_flags &= ~LDF_VLABEL; | | | |
353 | } | | | |
354 | | | 366 | |
355 | mutex_exit(&sc->sc_dk.dk_openlock); | | 367 | mutex_exit(&sc->sc_dk.dk_openlock); |
356 | return (0); | | 368 | return (0); |
357 | } | | 369 | } |
358 | | | 370 | |
359 | /* ARGSUSED */ | | 371 | /* ARGSUSED */ |
360 | static int | | 372 | static int |
361 | ldread(dev_t dev, struct uio *uio, int ioflag) | | 373 | ldread(dev_t dev, struct uio *uio, int ioflag) |
362 | { | | 374 | { |
363 | | | 375 | |
364 | return (physio(ldstrategy, NULL, dev, B_READ, ldminphys, uio)); | | 376 | return (physio(ldstrategy, NULL, dev, B_READ, ldminphys, uio)); |
365 | } | | 377 | } |
366 | | | 378 | |
367 | /* ARGSUSED */ | | 379 | /* ARGSUSED */ |
368 | static int | | 380 | static int |
369 | ldwrite(dev_t dev, struct uio *uio, int ioflag) | | 381 | ldwrite(dev_t dev, struct uio *uio, int ioflag) |
370 | { | | 382 | { |
371 | | | 383 | |
372 | return (physio(ldstrategy, NULL, dev, B_WRITE, ldminphys, uio)); | | 384 | return (physio(ldstrategy, NULL, dev, B_WRITE, ldminphys, uio)); |
373 | } | | 385 | } |
374 | | | 386 | |
375 | /* ARGSUSED */ | | 387 | /* ARGSUSED */ |
376 | static int | | 388 | static int |
377 | ldioctl(dev_t dev, u_long cmd, void *addr, int32_t flag, struct lwp *l) | | 389 | ldioctl(dev_t dev, u_long cmd, void *addr, int32_t flag, struct lwp *l) |
378 | { | | 390 | { |
379 | struct ld_softc *sc; | | 391 | struct ld_softc *sc; |
380 | int part, unit, error; | | 392 | int part, unit, error; |
381 | #ifdef __HAVE_OLD_DISKLABEL | | 393 | #ifdef __HAVE_OLD_DISKLABEL |
382 | struct disklabel newlabel; | | 394 | struct disklabel newlabel; |
383 | #endif | | 395 | #endif |
384 | struct disklabel *lp; | | 396 | struct disklabel *lp; |
385 | | | 397 | |
386 | unit = DISKUNIT(dev); | | 398 | unit = DISKUNIT(dev); |
387 | part = DISKPART(dev); | | 399 | part = DISKPART(dev); |
388 | sc = device_lookup_private(&ld_cd, unit); | | 400 | sc = device_lookup_private(&ld_cd, unit); |
389 | | | 401 | |
390 | error = disk_ioctl(&sc->sc_dk, cmd, addr, flag, l); | | 402 | error = disk_ioctl(&sc->sc_dk, cmd, addr, flag, l); |
391 | if (error != EPASSTHROUGH) | | 403 | if (error != EPASSTHROUGH) |
392 | return (error); | | 404 | return (error); |
393 | | | 405 | |
394 | error = 0; | | 406 | error = 0; |
395 | switch (cmd) { | | 407 | switch (cmd) { |
396 | case DIOCGDINFO: | | 408 | case DIOCGDINFO: |
397 | memcpy(addr, sc->sc_dk.dk_label, sizeof(struct disklabel)); | | 409 | memcpy(addr, sc->sc_dk.dk_label, sizeof(struct disklabel)); |
398 | return (0); | | 410 | return (0); |
399 | | | 411 | |
400 | #ifdef __HAVE_OLD_DISKLABEL | | 412 | #ifdef __HAVE_OLD_DISKLABEL |
401 | case ODIOCGDINFO: | | 413 | case ODIOCGDINFO: |
402 | newlabel = *(sc->sc_dk.dk_label); | | 414 | newlabel = *(sc->sc_dk.dk_label); |
403 | if (newlabel.d_npartitions > OLDMAXPARTITIONS) | | 415 | if (newlabel.d_npartitions > OLDMAXPARTITIONS) |
404 | return ENOTTY; | | 416 | return ENOTTY; |
405 | memcpy(addr, &newlabel, sizeof(struct olddisklabel)); | | 417 | memcpy(addr, &newlabel, sizeof(struct olddisklabel)); |
406 | return (0); | | 418 | return (0); |
407 | #endif | | 419 | #endif |
408 | | | 420 | |
409 | case DIOCGPART: | | 421 | case DIOCGPART: |
410 | ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label; | | 422 | ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label; |
411 | ((struct partinfo *)addr)->part = | | 423 | ((struct partinfo *)addr)->part = |
412 | &sc->sc_dk.dk_label->d_partitions[part]; | | 424 | &sc->sc_dk.dk_label->d_partitions[part]; |
413 | break; | | 425 | break; |
414 | | | 426 | |
415 | case DIOCWDINFO: | | 427 | case DIOCWDINFO: |
416 | case DIOCSDINFO: | | 428 | case DIOCSDINFO: |
417 | #ifdef __HAVE_OLD_DISKLABEL | | 429 | #ifdef __HAVE_OLD_DISKLABEL |
418 | case ODIOCWDINFO: | | 430 | case ODIOCWDINFO: |
419 | case ODIOCSDINFO: | | 431 | case ODIOCSDINFO: |
420 | | | 432 | |
421 | if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { | | 433 | if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { |
422 | memset(&newlabel, 0, sizeof newlabel); | | 434 | memset(&newlabel, 0, sizeof newlabel); |
423 | memcpy(&newlabel, addr, sizeof (struct olddisklabel)); | | 435 | memcpy(&newlabel, addr, sizeof (struct olddisklabel)); |
424 | lp = &newlabel; | | 436 | lp = &newlabel; |
425 | } else | | 437 | } else |
426 | #endif | | 438 | #endif |
427 | lp = (struct disklabel *)addr; | | 439 | lp = (struct disklabel *)addr; |
428 | | | 440 | |
429 | if ((flag & FWRITE) == 0) | | 441 | if ((flag & FWRITE) == 0) |
430 | return (EBADF); | | 442 | return (EBADF); |
431 | | | 443 | |
432 | mutex_enter(&sc->sc_dk.dk_openlock); | | 444 | mutex_enter(&sc->sc_dk.dk_openlock); |
433 | sc->sc_flags |= LDF_LABELLING; | | 445 | sc->sc_flags |= LDF_LABELLING; |
434 | | | 446 | |
435 | error = setdisklabel(sc->sc_dk.dk_label, | | 447 | error = setdisklabel(sc->sc_dk.dk_label, |
436 | lp, /*sc->sc_dk.dk_openmask : */0, | | 448 | lp, /*sc->sc_dk.dk_openmask : */0, |
437 | sc->sc_dk.dk_cpulabel); | | 449 | sc->sc_dk.dk_cpulabel); |
438 | if (error == 0 && (cmd == DIOCWDINFO | | 450 | if (error == 0 && (cmd == DIOCWDINFO |
439 | #ifdef __HAVE_OLD_DISKLABEL | | 451 | #ifdef __HAVE_OLD_DISKLABEL |
440 | || cmd == ODIOCWDINFO | | 452 | || cmd == ODIOCWDINFO |
441 | #endif | | 453 | #endif |
442 | )) | | 454 | )) |
443 | error = writedisklabel( | | 455 | error = writedisklabel( |
444 | MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART), | | 456 | MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART), |
445 | ldstrategy, sc->sc_dk.dk_label, | | 457 | ldstrategy, sc->sc_dk.dk_label, |
446 | sc->sc_dk.dk_cpulabel); | | 458 | sc->sc_dk.dk_cpulabel); |
447 | | | 459 | |
448 | sc->sc_flags &= ~LDF_LABELLING; | | 460 | sc->sc_flags &= ~LDF_LABELLING; |
449 | mutex_exit(&sc->sc_dk.dk_openlock); | | 461 | mutex_exit(&sc->sc_dk.dk_openlock); |
450 | break; | | 462 | break; |
451 | | | 463 | |
452 | case DIOCKLABEL: | | 464 | case DIOCKLABEL: |
453 | if ((flag & FWRITE) == 0) | | 465 | if ((flag & FWRITE) == 0) |
454 | return (EBADF); | | 466 | return (EBADF); |
455 | if (*(int *)addr) | | 467 | if (*(int *)addr) |
456 | sc->sc_flags |= LDF_KLABEL; | | 468 | sc->sc_flags |= LDF_KLABEL; |
457 | else | | 469 | else |
458 | sc->sc_flags &= ~LDF_KLABEL; | | 470 | sc->sc_flags &= ~LDF_KLABEL; |
459 | break; | | 471 | break; |
460 | | | 472 | |
461 | case DIOCWLABEL: | | 473 | case DIOCWLABEL: |
462 | if ((flag & FWRITE) == 0) | | 474 | if ((flag & FWRITE) == 0) |
463 | return (EBADF); | | 475 | return (EBADF); |
464 | if (*(int *)addr) | | 476 | if (*(int *)addr) |
465 | sc->sc_flags |= LDF_WLABEL; | | 477 | sc->sc_flags |= LDF_WLABEL; |
466 | else | | 478 | else |
467 | sc->sc_flags &= ~LDF_WLABEL; | | 479 | sc->sc_flags &= ~LDF_WLABEL; |
468 | break; | | 480 | break; |
469 | | | 481 | |
470 | case DIOCGDEFLABEL: | | 482 | case DIOCGDEFLABEL: |
471 | ldgetdefaultlabel(sc, (struct disklabel *)addr); | | 483 | ldgetdefaultlabel(sc, (struct disklabel *)addr); |
472 | break; | | 484 | break; |
473 | | | 485 | |
474 | #ifdef __HAVE_OLD_DISKLABEL | | 486 | #ifdef __HAVE_OLD_DISKLABEL |
475 | case ODIOCGDEFLABEL: | | 487 | case ODIOCGDEFLABEL: |
476 | ldgetdefaultlabel(sc, &newlabel); | | 488 | ldgetdefaultlabel(sc, &newlabel); |
477 | if (newlabel.d_npartitions > OLDMAXPARTITIONS) | | 489 | if (newlabel.d_npartitions > OLDMAXPARTITIONS) |
478 | return ENOTTY; | | 490 | return ENOTTY; |
479 | memcpy(addr, &newlabel, sizeof (struct olddisklabel)); | | 491 | memcpy(addr, &newlabel, sizeof (struct olddisklabel)); |
480 | break; | | 492 | break; |
481 | #endif | | 493 | #endif |
482 | | | 494 | |
483 | case DIOCCACHESYNC: | | 495 | case DIOCCACHESYNC: |
484 | /* | | 496 | /* |
485 | * XXX Do we really need to care about having a writable | | 497 | * XXX Do we really need to care about having a writable |
486 | * file descriptor here? | | 498 | * file descriptor here? |
487 | */ | | 499 | */ |
488 | if ((flag & FWRITE) == 0) | | 500 | if ((flag & FWRITE) == 0) |
489 | error = EBADF; | | 501 | error = EBADF; |
490 | else if (sc->sc_flush) | | 502 | else if (sc->sc_flush) |
491 | error = (*sc->sc_flush)(sc, 0); | | 503 | error = (*sc->sc_flush)(sc, 0); |
492 | else | | 504 | else |
493 | error = 0; /* XXX Error out instead? */ | | 505 | error = 0; /* XXX Error out instead? */ |
494 | break; | | 506 | break; |
495 | | | 507 | |
496 | case DIOCAWEDGE: | | 508 | case DIOCAWEDGE: |
497 | { | | 509 | { |
498 | struct dkwedge_info *dkw = (void *) addr; | | 510 | struct dkwedge_info *dkw = (void *) addr; |
499 | | | 511 | |
500 | if ((flag & FWRITE) == 0) | | 512 | if ((flag & FWRITE) == 0) |
501 | return (EBADF); | | 513 | return (EBADF); |
502 | | | 514 | |
503 | /* If the ioctl happens here, the parent is us. */ | | 515 | /* If the ioctl happens here, the parent is us. */ |
504 | strlcpy(dkw->dkw_parent, device_xname(sc->sc_dv), | | 516 | strlcpy(dkw->dkw_parent, device_xname(sc->sc_dv), |
505 | sizeof(dkw->dkw_parent)); | | 517 | sizeof(dkw->dkw_parent)); |
506 | return (dkwedge_add(dkw)); | | 518 | return (dkwedge_add(dkw)); |
507 | } | | 519 | } |
508 | | | 520 | |
509 | case DIOCDWEDGE: | | 521 | case DIOCDWEDGE: |
510 | { | | 522 | { |
511 | struct dkwedge_info *dkw = (void *) addr; | | 523 | struct dkwedge_info *dkw = (void *) addr; |
512 | | | 524 | |
513 | if ((flag & FWRITE) == 0) | | 525 | if ((flag & FWRITE) == 0) |
514 | return (EBADF); | | 526 | return (EBADF); |
515 | | | 527 | |
516 | /* If the ioctl happens here, the parent is us. */ | | 528 | /* If the ioctl happens here, the parent is us. */ |
517 | strlcpy(dkw->dkw_parent, device_xname(sc->sc_dv), | | 529 | strlcpy(dkw->dkw_parent, device_xname(sc->sc_dv), |
518 | sizeof(dkw->dkw_parent)); | | 530 | sizeof(dkw->dkw_parent)); |
519 | return (dkwedge_del(dkw)); | | 531 | return (dkwedge_del(dkw)); |
520 | } | | 532 | } |
521 | | | 533 | |
522 | case DIOCLWEDGES: | | 534 | case DIOCLWEDGES: |
523 | { | | 535 | { |
524 | struct dkwedge_list *dkwl = (void *) addr; | | 536 | struct dkwedge_list *dkwl = (void *) addr; |
525 | | | 537 | |
526 | return (dkwedge_list(&sc->sc_dk, dkwl, l)); | | 538 | return (dkwedge_list(&sc->sc_dk, dkwl, l)); |
527 | } | | 539 | } |
528 | case DIOCGSTRATEGY: | | 540 | case DIOCGSTRATEGY: |
529 | { | | 541 | { |
530 | struct disk_strategy *dks = (void *)addr; | | 542 | struct disk_strategy *dks = (void *)addr; |
531 | | | 543 | |
532 | mutex_enter(&sc->sc_mutex); | | 544 | mutex_enter(&sc->sc_mutex); |
533 | strlcpy(dks->dks_name, bufq_getstrategyname(sc->sc_bufq), | | 545 | strlcpy(dks->dks_name, bufq_getstrategyname(sc->sc_bufq), |
534 | sizeof(dks->dks_name)); | | 546 | sizeof(dks->dks_name)); |
535 | mutex_exit(&sc->sc_mutex); | | 547 | mutex_exit(&sc->sc_mutex); |
536 | dks->dks_paramlen = 0; | | 548 | dks->dks_paramlen = 0; |
537 | | | 549 | |
538 | return 0; | | 550 | return 0; |
539 | } | | 551 | } |
540 | case DIOCSSTRATEGY: | | 552 | case DIOCSSTRATEGY: |
541 | { | | 553 | { |
542 | struct disk_strategy *dks = (void *)addr; | | 554 | struct disk_strategy *dks = (void *)addr; |
543 | struct bufq_state *new, *old; | | 555 | struct bufq_state *new, *old; |
544 | | | 556 | |
545 | if ((flag & FWRITE) == 0) | | 557 | if ((flag & FWRITE) == 0) |
546 | return EPERM; | | 558 | return EPERM; |
547 | | | 559 | |
548 | if (dks->dks_param != NULL) | | 560 | if (dks->dks_param != NULL) |
549 | return EINVAL; | | 561 | return EINVAL; |
550 | | | 562 | |
551 | dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */ | | 563 | dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */ |
552 | error = bufq_alloc(&new, dks->dks_name, | | 564 | error = bufq_alloc(&new, dks->dks_name, |
553 | BUFQ_EXACT|BUFQ_SORT_RAWBLOCK); | | 565 | BUFQ_EXACT|BUFQ_SORT_RAWBLOCK); |
554 | if (error) | | 566 | if (error) |
555 | return error; | | 567 | return error; |
556 | | | 568 | |
557 | mutex_enter(&sc->sc_mutex); | | 569 | mutex_enter(&sc->sc_mutex); |
558 | old = sc->sc_bufq; | | 570 | old = sc->sc_bufq; |
559 | bufq_move(new, old); | | 571 | bufq_move(new, old); |
560 | sc->sc_bufq = new; | | 572 | sc->sc_bufq = new; |
561 | mutex_exit(&sc->sc_mutex); | | 573 | mutex_exit(&sc->sc_mutex); |
562 | bufq_free(old); | | 574 | bufq_free(old); |
563 | | | 575 | |
564 | return 0; | | 576 | return 0; |
565 | } | | 577 | } |
566 | default: | | 578 | default: |
567 | error = ENOTTY; | | 579 | error = ENOTTY; |
568 | break; | | 580 | break; |
569 | } | | 581 | } |
570 | | | 582 | |
571 | return (error); | | 583 | return (error); |
572 | } | | 584 | } |
573 | | | 585 | |
574 | static void | | 586 | static void |
575 | ldstrategy(struct buf *bp) | | 587 | ldstrategy(struct buf *bp) |
576 | { | | 588 | { |
577 | struct ld_softc *sc; | | 589 | struct ld_softc *sc; |
578 | struct disklabel *lp; | | 590 | struct disklabel *lp; |
579 | daddr_t blkno; | | 591 | daddr_t blkno; |
580 | int s, part; | | 592 | int s, part; |
581 | | | 593 | |
582 | sc = device_lookup_private(&ld_cd, DISKUNIT(bp->b_dev)); | | 594 | sc = device_lookup_private(&ld_cd, DISKUNIT(bp->b_dev)); |
583 | part = DISKPART(bp->b_dev); | | 595 | part = DISKPART(bp->b_dev); |
584 | | | 596 | |
585 | if ((sc->sc_flags & LDF_DETACH) != 0) { | | 597 | if ((sc->sc_flags & LDF_DETACH) != 0) { |
586 | bp->b_error = EIO; | | 598 | bp->b_error = EIO; |
587 | goto done; | | 599 | goto done; |
588 | } | | 600 | } |
589 | | | 601 | |
590 | lp = sc->sc_dk.dk_label; | | 602 | lp = sc->sc_dk.dk_label; |
591 | | | 603 | |
592 | /* | | 604 | /* |
593 | * The transfer must be a whole number of blocks and the offset must | | 605 | * The transfer must be a whole number of blocks and the offset must |
594 | * not be negative. | | 606 | * not be negative. |
595 | */ | | 607 | */ |
596 | if ((bp->b_bcount % lp->d_secsize) != 0 || bp->b_blkno < 0) { | | 608 | if ((bp->b_bcount % lp->d_secsize) != 0 || bp->b_blkno < 0) { |
597 | bp->b_error = EINVAL; | | 609 | bp->b_error = EINVAL; |
598 | goto done; | | 610 | goto done; |
599 | } | | 611 | } |
600 | | | 612 | |
601 | /* If it's a null transfer, return immediately. */ | | 613 | /* If it's a null transfer, return immediately. */ |
602 | if (bp->b_bcount == 0) | | 614 | if (bp->b_bcount == 0) |
603 | goto done; | | 615 | goto done; |
604 | | | 616 | |
605 | /* | | 617 | /* |
606 | * Do bounds checking and adjust the transfer. If error, process. | | 618 | * Do bounds checking and adjust the transfer. If error, process. |
607 | * If past the end of partition, just return. | | 619 | * If past the end of partition, just return. |
608 | */ | | 620 | */ |
609 | if (part != RAW_PART && | | 621 | if (part != RAW_PART && |
610 | bounds_check_with_label(&sc->sc_dk, bp, | | 622 | bounds_check_with_label(&sc->sc_dk, bp, |
611 | (sc->sc_flags & (LDF_WLABEL | LDF_LABELLING)) != 0) <= 0) { | | 623 | (sc->sc_flags & (LDF_WLABEL | LDF_LABELLING)) != 0) <= 0) { |
612 | goto done; | | 624 | goto done; |
613 | } | | 625 | } |
614 | | | 626 | |
615 | /* | | 627 | /* |
616 | * Convert the block number to absolute and put it in terms | | 628 | * Convert the block number to absolute and put it in terms |
617 | * of the device's logical block size. | | 629 | * of the device's logical block size. |
618 | */ | | 630 | */ |
619 | if (lp->d_secsize == DEV_BSIZE) | | 631 | if (lp->d_secsize == DEV_BSIZE) |
620 | blkno = bp->b_blkno; | | 632 | blkno = bp->b_blkno; |
621 | else if (lp->d_secsize > DEV_BSIZE) | | 633 | else if (lp->d_secsize > DEV_BSIZE) |
622 | blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); | | 634 | blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); |
623 | else | | 635 | else |
624 | blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize); | | 636 | blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize); |
625 | | | 637 | |
626 | if (part != RAW_PART) | | 638 | if (part != RAW_PART) |
627 | blkno += lp->d_partitions[part].p_offset; | | 639 | blkno += lp->d_partitions[part].p_offset; |
628 | | | 640 | |
629 | bp->b_rawblkno = blkno; | | 641 | bp->b_rawblkno = blkno; |
630 | | | 642 | |
631 | s = splbio(); | | 643 | s = splbio(); |
632 | ldstart(sc, bp); | | 644 | ldstart(sc, bp); |
633 | splx(s); | | 645 | splx(s); |
634 | return; | | 646 | return; |
635 | | | 647 | |
636 | done: | | 648 | done: |
637 | bp->b_resid = bp->b_bcount; | | 649 | bp->b_resid = bp->b_bcount; |
638 | biodone(bp); | | 650 | biodone(bp); |
639 | } | | 651 | } |
640 | | | 652 | |
641 | static void | | 653 | static void |
642 | ldstart(struct ld_softc *sc, struct buf *bp) | | 654 | ldstart(struct ld_softc *sc, struct buf *bp) |
643 | { | | 655 | { |
644 | int error; | | 656 | int error; |
645 | | | 657 | |
646 | mutex_enter(&sc->sc_mutex); | | 658 | mutex_enter(&sc->sc_mutex); |
647 | | | 659 | |
648 | if (bp != NULL) | | 660 | if (bp != NULL) |
649 | bufq_put(sc->sc_bufq, bp); | | 661 | bufq_put(sc->sc_bufq, bp); |
650 | | | 662 | |
651 | while (sc->sc_queuecnt < sc->sc_maxqueuecnt) { | | 663 | while (sc->sc_queuecnt < sc->sc_maxqueuecnt) { |
652 | /* See if there is work to do. */ | | 664 | /* See if there is work to do. */ |
653 | if ((bp = bufq_peek(sc->sc_bufq)) == NULL) | | 665 | if ((bp = bufq_peek(sc->sc_bufq)) == NULL) |
654 | break; | | 666 | break; |
655 | | | 667 | |
656 | disk_busy(&sc->sc_dk); | | 668 | disk_busy(&sc->sc_dk); |
657 | sc->sc_queuecnt++; | | 669 | sc->sc_queuecnt++; |
658 | | | 670 | |
659 | if (__predict_true((error = (*sc->sc_start)(sc, bp)) == 0)) { | | 671 | if (__predict_true((error = (*sc->sc_start)(sc, bp)) == 0)) { |
660 | /* | | 672 | /* |
661 | * The back-end is running the job; remove it from | | 673 | * The back-end is running the job; remove it from |
662 | * the queue. | | 674 | * the queue. |
663 | */ | | 675 | */ |
664 | (void) bufq_get(sc->sc_bufq); | | 676 | (void) bufq_get(sc->sc_bufq); |
665 | } else { | | 677 | } else { |
666 | disk_unbusy(&sc->sc_dk, 0, (bp->b_flags & B_READ)); | | 678 | disk_unbusy(&sc->sc_dk, 0, (bp->b_flags & B_READ)); |
667 | sc->sc_queuecnt--; | | 679 | sc->sc_queuecnt--; |
668 | if (error == EAGAIN) { | | 680 | if (error == EAGAIN) { |
669 | /* | | 681 | /* |
670 | * Temporary resource shortage in the | | 682 | * Temporary resource shortage in the |
671 | * back-end; just defer the job until | | 683 | * back-end; just defer the job until |
672 | * later. | | 684 | * later. |
673 | * | | 685 | * |
674 | * XXX We might consider a watchdog timer | | 686 | * XXX We might consider a watchdog timer |
675 | * XXX to make sure we are kicked into action. | | 687 | * XXX to make sure we are kicked into action. |
676 | */ | | 688 | */ |
677 | break; | | 689 | break; |
678 | } else { | | 690 | } else { |
679 | (void) bufq_get(sc->sc_bufq); | | 691 | (void) bufq_get(sc->sc_bufq); |
680 | bp->b_error = error; | | 692 | bp->b_error = error; |
681 | bp->b_resid = bp->b_bcount; | | 693 | bp->b_resid = bp->b_bcount; |
682 | mutex_exit(&sc->sc_mutex); | | 694 | mutex_exit(&sc->sc_mutex); |
683 | biodone(bp); | | 695 | biodone(bp); |
684 | mutex_enter(&sc->sc_mutex); | | 696 | mutex_enter(&sc->sc_mutex); |
685 | } | | 697 | } |
686 | } | | 698 | } |
687 | } | | 699 | } |
688 | | | 700 | |
689 | mutex_exit(&sc->sc_mutex); | | 701 | mutex_exit(&sc->sc_mutex); |
690 | } | | 702 | } |
691 | | | 703 | |
692 | void | | 704 | void |
693 | lddone(struct ld_softc *sc, struct buf *bp) | | 705 | lddone(struct ld_softc *sc, struct buf *bp) |
694 | { | | 706 | { |
695 | | | 707 | |
696 | if (bp->b_error != 0) { | | 708 | if (bp->b_error != 0) { |
697 | diskerr(bp, "ld", "error", LOG_PRINTF, 0, sc->sc_dk.dk_label); | | 709 | diskerr(bp, "ld", "error", LOG_PRINTF, 0, sc->sc_dk.dk_label); |
698 | printf("\n"); | | 710 | printf("\n"); |
699 | } | | 711 | } |
700 | | | 712 | |
701 | disk_unbusy(&sc->sc_dk, bp->b_bcount - bp->b_resid, | | 713 | disk_unbusy(&sc->sc_dk, bp->b_bcount - bp->b_resid, |
702 | (bp->b_flags & B_READ)); | | 714 | (bp->b_flags & B_READ)); |
703 | #if NRND > 0 | | 715 | #if NRND > 0 |
704 | rnd_add_uint32(&sc->sc_rnd_source, bp->b_rawblkno); | | 716 | rnd_add_uint32(&sc->sc_rnd_source, bp->b_rawblkno); |
705 | #endif | | 717 | #endif |
706 | biodone(bp); | | 718 | biodone(bp); |
707 | | | 719 | |
708 | mutex_enter(&sc->sc_mutex); | | 720 | mutex_enter(&sc->sc_mutex); |
709 | if (--sc->sc_queuecnt <= sc->sc_maxqueuecnt) { | | 721 | if (--sc->sc_queuecnt <= sc->sc_maxqueuecnt) { |
710 | if ((sc->sc_flags & LDF_DRAIN) != 0) { | | 722 | if ((sc->sc_flags & LDF_DRAIN) != 0) { |
711 | sc->sc_flags &= ~LDF_DRAIN; | | 723 | sc->sc_flags &= ~LDF_DRAIN; |
712 | wakeup(&sc->sc_queuecnt); | | 724 | wakeup(&sc->sc_queuecnt); |
713 | } | | 725 | } |
714 | mutex_exit(&sc->sc_mutex); | | 726 | mutex_exit(&sc->sc_mutex); |
715 | ldstart(sc, NULL); | | 727 | ldstart(sc, NULL); |
716 | } else | | 728 | } else |
717 | mutex_exit(&sc->sc_mutex); | | 729 | mutex_exit(&sc->sc_mutex); |
718 | } | | 730 | } |
719 | | | 731 | |
720 | static int | | 732 | static int |
721 | ldsize(dev_t dev) | | 733 | ldsize(dev_t dev) |
722 | { | | 734 | { |
723 | struct ld_softc *sc; | | 735 | struct ld_softc *sc; |
724 | int part, unit, omask, size; | | 736 | int part, unit, omask, size; |
725 | | | 737 | |
726 | unit = DISKUNIT(dev); | | 738 | unit = DISKUNIT(dev); |
727 | if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) | | 739 | if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) |
728 | return (ENODEV); | | 740 | return (ENODEV); |
729 | if ((sc->sc_flags & LDF_ENABLED) == 0) | | 741 | if ((sc->sc_flags & LDF_ENABLED) == 0) |
730 | return (ENODEV); | | 742 | return (ENODEV); |
731 | part = DISKPART(dev); | | 743 | part = DISKPART(dev); |
732 | | | 744 | |
733 | omask = sc->sc_dk.dk_openmask & (1 << part); | | 745 | omask = sc->sc_dk.dk_openmask & (1 << part); |
734 | | | 746 | |
735 | if (omask == 0 && ldopen(dev, 0, S_IFBLK, NULL) != 0) | | 747 | if (omask == 0 && ldopen(dev, 0, S_IFBLK, NULL) != 0) |
736 | return (-1); | | 748 | return (-1); |
737 | else if (sc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) | | 749 | else if (sc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) |
738 | size = -1; | | 750 | size = -1; |
739 | else | | 751 | else |
740 | size = sc->sc_dk.dk_label->d_partitions[part].p_size * | | 752 | size = sc->sc_dk.dk_label->d_partitions[part].p_size * |
741 | (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE); | | 753 | (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE); |
742 | if (omask == 0 && ldclose(dev, 0, S_IFBLK, NULL) != 0) | | 754 | if (omask == 0 && ldclose(dev, 0, S_IFBLK, NULL) != 0) |
743 | return (-1); | | 755 | return (-1); |
744 | | | 756 | |
745 | return (size); | | 757 | return (size); |
746 | } | | 758 | } |
747 | | | 759 | |
748 | /* | | 760 | /* |
749 | * Load the label information from the specified device. | | 761 | * Load the label information from the specified device. |
750 | */ | | 762 | */ |
751 | static void | | 763 | static void |
752 | ldgetdisklabel(struct ld_softc *sc) | | 764 | ldgetdisklabel(struct ld_softc *sc) |
753 | { | | 765 | { |
754 | const char *errstring; | | 766 | const char *errstring; |
755 | | | 767 | |
756 | ldgetdefaultlabel(sc, sc->sc_dk.dk_label); | | 768 | ldgetdefaultlabel(sc, sc->sc_dk.dk_label); |
757 | | | 769 | |
758 | /* Call the generic disklabel extraction routine. */ | | 770 | /* Call the generic disklabel extraction routine. */ |
759 | errstring = readdisklabel(MAKEDISKDEV(0, device_unit(sc->sc_dv), | | 771 | errstring = readdisklabel(MAKEDISKDEV(0, device_unit(sc->sc_dv), |
760 | RAW_PART), ldstrategy, sc->sc_dk.dk_label, sc->sc_dk.dk_cpulabel); | | 772 | RAW_PART), ldstrategy, sc->sc_dk.dk_label, sc->sc_dk.dk_cpulabel); |
761 | if (errstring != NULL) | | 773 | if (errstring != NULL) |
762 | printf("%s: %s\n", device_xname(sc->sc_dv), errstring); | | 774 | printf("%s: %s\n", device_xname(sc->sc_dv), errstring); |
763 | | | 775 | |
764 | /* In-core label now valid. */ | | 776 | /* In-core label now valid. */ |
765 | sc->sc_flags |= LDF_VLABEL; | | 777 | sc->sc_flags |= LDF_VLABEL; |
766 | } | | 778 | } |
767 | | | 779 | |
768 | /* | | 780 | /* |
769 | * Construct a ficticious label. | | 781 | * Construct a ficticious label. |
770 | */ | | 782 | */ |
771 | static void | | 783 | static void |
772 | ldgetdefaultlabel(struct ld_softc *sc, struct disklabel *lp) | | 784 | ldgetdefaultlabel(struct ld_softc *sc, struct disklabel *lp) |
773 | { | | 785 | { |
774 | | | 786 | |
775 | memset(lp, 0, sizeof(struct disklabel)); | | 787 | memset(lp, 0, sizeof(struct disklabel)); |
776 | | | 788 | |
777 | lp->d_secsize = sc->sc_secsize; | | 789 | lp->d_secsize = sc->sc_secsize; |
778 | lp->d_ntracks = sc->sc_nheads; | | 790 | lp->d_ntracks = sc->sc_nheads; |
779 | lp->d_nsectors = sc->sc_nsectors; | | 791 | lp->d_nsectors = sc->sc_nsectors; |
780 | lp->d_ncylinders = sc->sc_ncylinders; | | 792 | lp->d_ncylinders = sc->sc_ncylinders; |
781 | lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; | | 793 | lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; |
782 | lp->d_type = DTYPE_LD; | | 794 | lp->d_type = DTYPE_LD; |
783 | strlcpy(lp->d_typename, "unknown", sizeof(lp->d_typename)); | | 795 | strlcpy(lp->d_typename, "unknown", sizeof(lp->d_typename)); |
784 | strlcpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); | | 796 | strlcpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); |
785 | lp->d_secperunit = sc->sc_secperunit; | | 797 | lp->d_secperunit = sc->sc_secperunit; |
786 | lp->d_rpm = 7200; | | 798 | lp->d_rpm = 7200; |
787 | lp->d_interleave = 1; | | 799 | lp->d_interleave = 1; |
788 | lp->d_flags = 0; | | 800 | lp->d_flags = 0; |
789 | | | 801 | |
790 | lp->d_partitions[RAW_PART].p_offset = 0; | | 802 | lp->d_partitions[RAW_PART].p_offset = 0; |
791 | lp->d_partitions[RAW_PART].p_size = | | 803 | lp->d_partitions[RAW_PART].p_size = |
792 | lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); | | 804 | lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); |
793 | lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; | | 805 | lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; |
794 | lp->d_npartitions = RAW_PART + 1; | | 806 | lp->d_npartitions = RAW_PART + 1; |
795 | | | 807 | |
796 | lp->d_magic = DISKMAGIC; | | 808 | lp->d_magic = DISKMAGIC; |
797 | lp->d_magic2 = DISKMAGIC; | | 809 | lp->d_magic2 = DISKMAGIC; |
798 | lp->d_checksum = dkcksum(lp); | | 810 | lp->d_checksum = dkcksum(lp); |
799 | } | | 811 | } |
800 | | | 812 | |
801 | /* | | 813 | /* |
802 | * Take a dump. | | 814 | * Take a dump. |
803 | */ | | 815 | */ |
804 | static int | | 816 | static int |
805 | lddump(dev_t dev, daddr_t blkno, void *vav, size_t size) | | 817 | lddump(dev_t dev, daddr_t blkno, void *vav, size_t size) |
806 | { | | 818 | { |
807 | char *va = vav; | | 819 | char *va = vav; |
808 | struct ld_softc *sc; | | 820 | struct ld_softc *sc; |
809 | struct disklabel *lp; | | 821 | struct disklabel *lp; |
810 | int unit, part, nsects, sectoff, towrt, nblk, maxblkcnt, rv; | | 822 | int unit, part, nsects, sectoff, towrt, nblk, maxblkcnt, rv; |
811 | static int dumping; | | 823 | static int dumping; |
812 | | | 824 | |
813 | unit = DISKUNIT(dev); | | 825 | unit = DISKUNIT(dev); |
814 | if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) | | 826 | if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) |
815 | return (ENXIO); | | 827 | return (ENXIO); |
816 | if ((sc->sc_flags & LDF_ENABLED) == 0) | | 828 | if ((sc->sc_flags & LDF_ENABLED) == 0) |
817 | return (ENODEV); | | 829 | return (ENODEV); |
818 | if (sc->sc_dump == NULL) | | 830 | if (sc->sc_dump == NULL) |
819 | return (ENXIO); | | 831 | return (ENXIO); |
820 | | | 832 | |
821 | /* Check if recursive dump; if so, punt. */ | | 833 | /* Check if recursive dump; if so, punt. */ |
822 | if (dumping) | | 834 | if (dumping) |
823 | return (EFAULT); | | 835 | return (EFAULT); |
824 | dumping = 1; | | 836 | dumping = 1; |
825 | | | 837 | |
826 | /* Convert to disk sectors. Request must be a multiple of size. */ | | 838 | /* Convert to disk sectors. Request must be a multiple of size. */ |
827 | part = DISKPART(dev); | | 839 | part = DISKPART(dev); |
828 | lp = sc->sc_dk.dk_label; | | 840 | lp = sc->sc_dk.dk_label; |
829 | if ((size % lp->d_secsize) != 0) | | 841 | if ((size % lp->d_secsize) != 0) |
830 | return (EFAULT); | | 842 | return (EFAULT); |
831 | towrt = size / lp->d_secsize; | | 843 | towrt = size / lp->d_secsize; |
832 | blkno = dbtob(blkno) / lp->d_secsize; /* blkno in DEV_BSIZE units */ | | 844 | blkno = dbtob(blkno) / lp->d_secsize; /* blkno in DEV_BSIZE units */ |
833 | | | 845 | |
834 | nsects = lp->d_partitions[part].p_size; | | 846 | nsects = lp->d_partitions[part].p_size; |
835 | sectoff = lp->d_partitions[part].p_offset; | | 847 | sectoff = lp->d_partitions[part].p_offset; |
836 | | | 848 | |
837 | /* Check transfer bounds against partition size. */ | | 849 | /* Check transfer bounds against partition size. */ |
838 | if ((blkno < 0) || ((blkno + towrt) > nsects)) | | 850 | if ((blkno < 0) || ((blkno + towrt) > nsects)) |
839 | return (EINVAL); | | 851 | return (EINVAL); |
840 | | | 852 | |
841 | /* Offset block number to start of partition. */ | | 853 | /* Offset block number to start of partition. */ |
842 | blkno += sectoff; | | 854 | blkno += sectoff; |
843 | | | 855 | |
844 | /* Start dumping and return when done. */ | | 856 | /* Start dumping and return when done. */ |
845 | maxblkcnt = sc->sc_maxxfer / sc->sc_secsize - 1; | | 857 | maxblkcnt = sc->sc_maxxfer / sc->sc_secsize - 1; |
846 | while (towrt > 0) { | | 858 | while (towrt > 0) { |
847 | nblk = min(maxblkcnt, towrt); | | 859 | nblk = min(maxblkcnt, towrt); |
848 | | | 860 | |
849 | if ((rv = (*sc->sc_dump)(sc, va, blkno, nblk)) != 0) | | 861 | if ((rv = (*sc->sc_dump)(sc, va, blkno, nblk)) != 0) |
850 | return (rv); | | 862 | return (rv); |
851 | | | 863 | |
852 | towrt -= nblk; | | 864 | towrt -= nblk; |
853 | blkno += nblk; | | 865 | blkno += nblk; |
854 | va += nblk * sc->sc_secsize; | | 866 | va += nblk * sc->sc_secsize; |
855 | } | | 867 | } |
856 | | | 868 | |
857 | dumping = 0; | | 869 | dumping = 0; |
858 | return (0); | | 870 | return (0); |
859 | } | | 871 | } |
860 | | | 872 | |
861 | /* | | 873 | /* |
862 | * Adjust the size of a transfer. | | 874 | * Adjust the size of a transfer. |
863 | */ | | 875 | */ |
864 | static void | | 876 | static void |
865 | ldminphys(struct buf *bp) | | 877 | ldminphys(struct buf *bp) |
866 | { | | 878 | { |
867 | struct ld_softc *sc; | | 879 | struct ld_softc *sc; |
868 | | | 880 | |
869 | sc = device_lookup_private(&ld_cd, DISKUNIT(bp->b_dev)); | | 881 | sc = device_lookup_private(&ld_cd, DISKUNIT(bp->b_dev)); |
870 | | | 882 | |
871 | if (bp->b_bcount > sc->sc_maxxfer) | | 883 | if (bp->b_bcount > sc->sc_maxxfer) |
872 | bp->b_bcount = sc->sc_maxxfer; | | 884 | bp->b_bcount = sc->sc_maxxfer; |
873 | minphys(bp); | | 885 | minphys(bp); |
874 | } | | 886 | } |
875 | | | 887 | |
876 | static void | | 888 | static void |
877 | ld_set_properties(struct ld_softc *ld) | | 889 | ld_set_properties(struct ld_softc *ld) |
878 | { | | 890 | { |
879 | prop_dictionary_t disk_info, odisk_info, geom; | | 891 | prop_dictionary_t disk_info, odisk_info, geom; |
880 | | | 892 | |
881 | disk_info = prop_dictionary_create(); | | 893 | disk_info = prop_dictionary_create(); |
882 | | | 894 | |
883 | geom = prop_dictionary_create(); | | 895 | geom = prop_dictionary_create(); |
884 | | | 896 | |
885 | prop_dictionary_set_uint64(geom, "sectors-per-unit", | | 897 | prop_dictionary_set_uint64(geom, "sectors-per-unit", |
886 | ld->sc_secperunit); | | 898 | ld->sc_secperunit); |
887 | | | 899 | |
888 | prop_dictionary_set_uint32(geom, "sector-size", | | 900 | prop_dictionary_set_uint32(geom, "sector-size", |
889 | ld->sc_secsize); | | 901 | ld->sc_secsize); |
890 | | | 902 | |
891 | prop_dictionary_set_uint16(geom, "sectors-per-track", | | 903 | prop_dictionary_set_uint16(geom, "sectors-per-track", |
892 | ld->sc_nsectors); | | 904 | ld->sc_nsectors); |
893 | | | 905 | |
894 | prop_dictionary_set_uint16(geom, "tracks-per-cylinder", | | 906 | prop_dictionary_set_uint16(geom, "tracks-per-cylinder", |
895 | ld->sc_nheads); | | 907 | ld->sc_nheads); |
896 | | | 908 | |
897 | prop_dictionary_set_uint64(geom, "cylinders-per-unit", | | 909 | prop_dictionary_set_uint64(geom, "cylinders-per-unit", |
898 | ld->sc_ncylinders); | | 910 | ld->sc_ncylinders); |
899 | | | 911 | |
900 | prop_dictionary_set(disk_info, "geometry", geom); | | 912 | prop_dictionary_set(disk_info, "geometry", geom); |
901 | prop_object_release(geom); | | 913 | prop_object_release(geom); |
902 | | | 914 | |
903 | prop_dictionary_set(device_properties(ld->sc_dv), | | 915 | prop_dictionary_set(device_properties(ld->sc_dv), |
904 | "disk-info", disk_info); | | 916 | "disk-info", disk_info); |
905 | | | 917 | |
906 | /* | | 918 | /* |
907 | * Don't release disk_info here; we keep a reference to it. | | 919 | * Don't release disk_info here; we keep a reference to it. |
908 | * disk_detach() will release it when we go away. | | 920 | * disk_detach() will release it when we go away. |
909 | */ | | 921 | */ |
910 | | | 922 | |
911 | odisk_info = ld->sc_dk.dk_info; | | 923 | odisk_info = ld->sc_dk.dk_info; |
912 | ld->sc_dk.dk_info = disk_info; | | 924 | ld->sc_dk.dk_info = disk_info; |
913 | if (odisk_info) | | 925 | if (odisk_info) |
914 | prop_object_release(odisk_info); | | 926 | prop_object_release(odisk_info); |
915 | } | | 927 | } |
916 | | | 928 | |
917 | static void | | 929 | static void |
918 | ld_config_interrupts(device_t d) | | 930 | ld_config_interrupts(device_t d) |
919 | { | | 931 | { |
920 | struct ld_softc *sc = device_private(d); | | 932 | struct ld_softc *sc = device_private(d); |
921 | dkwedge_discover(&sc->sc_dk); | | 933 | dkwedge_discover(&sc->sc_dk); |
922 | } | | 934 | } |