ofdisk.c revision 1.37.10.2 1 1.37.10.2 ad /* $NetBSD: ofdisk.c,v 1.37.10.2 2007/07/29 12:15:44 ad Exp $ */
2 1.37.10.2 ad
3 1.37.10.2 ad /*
4 1.37.10.2 ad * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5 1.37.10.2 ad * Copyright (C) 1995, 1996 TooLs GmbH.
6 1.37.10.2 ad * All rights reserved.
7 1.37.10.2 ad *
8 1.37.10.2 ad * Redistribution and use in source and binary forms, with or without
9 1.37.10.2 ad * modification, are permitted provided that the following conditions
10 1.37.10.2 ad * are met:
11 1.37.10.2 ad * 1. Redistributions of source code must retain the above copyright
12 1.37.10.2 ad * notice, this list of conditions and the following disclaimer.
13 1.37.10.2 ad * 2. Redistributions in binary form must reproduce the above copyright
14 1.37.10.2 ad * notice, this list of conditions and the following disclaimer in the
15 1.37.10.2 ad * documentation and/or other materials provided with the distribution.
16 1.37.10.2 ad * 3. All advertising materials mentioning features or use of this software
17 1.37.10.2 ad * must display the following acknowledgement:
18 1.37.10.2 ad * This product includes software developed by TooLs GmbH.
19 1.37.10.2 ad * 4. The name of TooLs GmbH may not be used to endorse or promote products
20 1.37.10.2 ad * derived from this software without specific prior written permission.
21 1.37.10.2 ad *
22 1.37.10.2 ad * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23 1.37.10.2 ad * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 1.37.10.2 ad * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 1.37.10.2 ad * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 1.37.10.2 ad * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 1.37.10.2 ad * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 1.37.10.2 ad * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 1.37.10.2 ad * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 1.37.10.2 ad * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 1.37.10.2 ad * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 1.37.10.2 ad */
33 1.37.10.2 ad
34 1.37.10.2 ad #include <sys/cdefs.h>
35 1.37.10.2 ad __KERNEL_RCSID(0, "$NetBSD: ofdisk.c,v 1.37.10.2 2007/07/29 12:15:44 ad Exp $");
36 1.37.10.2 ad
37 1.37.10.2 ad #include <sys/param.h>
38 1.37.10.2 ad #include <sys/buf.h>
39 1.37.10.2 ad #include <sys/device.h>
40 1.37.10.2 ad #include <sys/conf.h>
41 1.37.10.2 ad #include <sys/disklabel.h>
42 1.37.10.2 ad #include <sys/disk.h>
43 1.37.10.2 ad #include <sys/fcntl.h>
44 1.37.10.2 ad #include <sys/ioctl.h>
45 1.37.10.2 ad #include <sys/stat.h>
46 1.37.10.2 ad #include <sys/systm.h>
47 1.37.10.2 ad #include <sys/proc.h>
48 1.37.10.2 ad
49 1.37.10.2 ad #include <dev/ofw/openfirm.h>
50 1.37.10.2 ad
51 1.37.10.2 ad struct ofdisk_softc {
52 1.37.10.2 ad struct device sc_dev;
53 1.37.10.2 ad int sc_phandle;
54 1.37.10.2 ad int sc_unit;
55 1.37.10.2 ad int sc_flags;
56 1.37.10.2 ad struct disk sc_dk;
57 1.37.10.2 ad int sc_ihandle;
58 1.37.10.2 ad u_long max_transfer;
59 1.37.10.2 ad };
60 1.37.10.2 ad
61 1.37.10.2 ad /* sc_flags */
62 1.37.10.2 ad #define OFDF_ISFLOPPY 0x01 /* we are a floppy drive */
63 1.37.10.2 ad
64 1.37.10.2 ad #define OFDISK_FLOPPY_P(of) ((of)->sc_flags & OFDF_ISFLOPPY)
65 1.37.10.2 ad
66 1.37.10.2 ad static int ofdisk_match (struct device *, struct cfdata *, void *);
67 1.37.10.2 ad static void ofdisk_attach (struct device *, struct device *, void *);
68 1.37.10.2 ad
69 1.37.10.2 ad CFATTACH_DECL(ofdisk, sizeof(struct ofdisk_softc),
70 1.37.10.2 ad ofdisk_match, ofdisk_attach, NULL, NULL);
71 1.37.10.2 ad
72 1.37.10.2 ad extern struct cfdriver ofdisk_cd;
73 1.37.10.2 ad
74 1.37.10.2 ad dev_type_open(ofdisk_open);
75 1.37.10.2 ad dev_type_close(ofdisk_close);
76 1.37.10.2 ad dev_type_read(ofdisk_read);
77 1.37.10.2 ad dev_type_write(ofdisk_write);
78 1.37.10.2 ad dev_type_ioctl(ofdisk_ioctl);
79 1.37.10.2 ad dev_type_strategy(ofdisk_strategy);
80 1.37.10.2 ad dev_type_dump(ofdisk_dump);
81 1.37.10.2 ad dev_type_size(ofdisk_size);
82 1.37.10.2 ad
83 1.37.10.2 ad const struct bdevsw ofdisk_bdevsw = {
84 1.37.10.2 ad ofdisk_open, ofdisk_close, ofdisk_strategy, ofdisk_ioctl,
85 1.37.10.2 ad ofdisk_dump, ofdisk_size, D_DISK
86 1.37.10.2 ad };
87 1.37.10.2 ad
88 1.37.10.2 ad const struct cdevsw ofdisk_cdevsw = {
89 1.37.10.2 ad ofdisk_open, ofdisk_close, ofdisk_read, ofdisk_write, ofdisk_ioctl,
90 1.37.10.2 ad nostop, notty, nopoll, nommap, nokqfilter, D_DISK
91 1.37.10.2 ad };
92 1.37.10.2 ad
93 1.37.10.2 ad static void ofminphys(struct buf *);
94 1.37.10.2 ad
95 1.37.10.2 ad struct dkdriver ofdisk_dkdriver = { ofdisk_strategy, ofminphys };
96 1.37.10.2 ad
97 1.37.10.2 ad void ofdisk_getdefaultlabel (struct ofdisk_softc *, struct disklabel *);
98 1.37.10.2 ad void ofdisk_getdisklabel (dev_t);
99 1.37.10.2 ad
100 1.37.10.2 ad static int
101 1.37.10.2 ad ofdisk_match(struct device *parent, struct cfdata *match, void *aux)
102 1.37.10.2 ad {
103 1.37.10.2 ad struct ofbus_attach_args *oba = aux;
104 1.37.10.2 ad char type[8];
105 1.37.10.2 ad int l;
106 1.37.10.2 ad
107 1.37.10.2 ad if (strcmp(oba->oba_busname, "ofw"))
108 1.37.10.2 ad return (0);
109 1.37.10.2 ad if ((l = OF_getprop(oba->oba_phandle, "device_type", type,
110 1.37.10.2 ad sizeof type - 1)) < 0)
111 1.37.10.2 ad return 0;
112 1.37.10.2 ad if (l >= sizeof type)
113 1.37.10.2 ad return 0;
114 1.37.10.2 ad type[l] = 0;
115 1.37.10.2 ad return !strcmp(type, "block");
116 1.37.10.2 ad }
117 1.37.10.2 ad
118 1.37.10.2 ad static void
119 1.37.10.2 ad ofdisk_attach(struct device *parent, struct device *self, void *aux)
120 1.37.10.2 ad {
121 1.37.10.2 ad struct ofdisk_softc *of = device_private(self);
122 1.37.10.2 ad struct ofbus_attach_args *oba = aux;
123 1.37.10.2 ad char child[64];
124 1.37.10.2 ad int l;
125 1.37.10.2 ad
126 1.37.10.2 ad if ((l = OF_getprop(oba->oba_phandle, "name", child,
127 1.37.10.2 ad sizeof child - 1)) < 0)
128 1.37.10.2 ad panic("device without name?");
129 1.37.10.2 ad if (l >= sizeof child)
130 1.37.10.2 ad l = sizeof child - 1;
131 1.37.10.2 ad child[l] = 0;
132 1.37.10.2 ad
133 1.37.10.2 ad of->sc_flags = 0;
134 1.37.10.2 ad of->sc_phandle = oba->oba_phandle;
135 1.37.10.2 ad of->sc_unit = oba->oba_unit;
136 1.37.10.2 ad of->sc_ihandle = 0;
137 1.37.10.2 ad of->sc_dk.dk_driver = &ofdisk_dkdriver;
138 1.37.10.2 ad of->sc_dk.dk_name = of->sc_dev.dv_xname;
139 1.37.10.2 ad disk_attach(&of->sc_dk);
140 1.37.10.2 ad printf("\n");
141 1.37.10.2 ad
142 1.37.10.2 ad if (strcmp(child, "floppy") == 0)
143 1.37.10.2 ad of->sc_flags |= OFDF_ISFLOPPY;
144 1.37.10.2 ad else {
145 1.37.10.2 ad /* Discover wedges on this disk. */
146 1.37.10.2 ad dkwedge_discover(&of->sc_dk);
147 1.37.10.2 ad }
148 1.37.10.2 ad }
149 1.37.10.2 ad
150 1.37.10.2 ad int
151 1.37.10.2 ad ofdisk_open(dev_t dev, int flags, int fmt, struct lwp *lwp)
152 1.37.10.2 ad {
153 1.37.10.2 ad int unit = DISKUNIT(dev);
154 1.37.10.2 ad struct ofdisk_softc *of;
155 1.37.10.2 ad char path[256];
156 1.37.10.2 ad int error, l, part;
157 1.37.10.2 ad
158 1.37.10.2 ad if (unit >= ofdisk_cd.cd_ndevs)
159 1.37.10.2 ad return ENXIO;
160 1.37.10.2 ad if (!(of = ofdisk_cd.cd_devs[unit]))
161 1.37.10.2 ad return ENXIO;
162 1.37.10.2 ad
163 1.37.10.2 ad part = DISKPART(dev);
164 1.37.10.2 ad
165 1.37.10.2 ad mutex_enter(&of->sc_dk.dk_openlock);
166 1.37.10.2 ad
167 1.37.10.2 ad /*
168 1.37.10.2 ad * If there are wedges, and this is not RAW_PART, then we
169 1.37.10.2 ad * need to fail.
170 1.37.10.2 ad */
171 1.37.10.2 ad if (of->sc_dk.dk_nwedges != 0 && part != RAW_PART) {
172 1.37.10.2 ad error = EBUSY;
173 1.37.10.2 ad goto bad1;
174 1.37.10.2 ad }
175 1.37.10.2 ad
176 1.37.10.2 ad if (!of->sc_ihandle) {
177 1.37.10.2 ad if ((l = OF_package_to_path(of->sc_phandle, path,
178 1.37.10.2 ad sizeof path - 3)) < 0 ||
179 1.37.10.2 ad l >= sizeof path - 3) {
180 1.37.10.2 ad error = ENXIO;
181 1.37.10.2 ad goto bad1;
182 1.37.10.2 ad }
183 1.37.10.2 ad path[l] = 0;
184 1.37.10.2 ad
185 1.37.10.2 ad /*
186 1.37.10.2 ad * XXX This is for the benefit of SCSI/IDE disks that don't
187 1.37.10.2 ad * XXX have all their childs in the device tree.
188 1.37.10.2 ad * XXX YES, I DO THINK THIS IS A BUG IN OPENFIRMWARE!!!
189 1.37.10.2 ad * XXX And yes, this is a very gross hack!
190 1.37.10.2 ad * XXX See also ofscsi.c
191 1.37.10.2 ad */
192 1.37.10.2 ad if (!strcmp(path + l - 4, "disk")) {
193 1.37.10.2 ad path[l++] = '@';
194 1.37.10.2 ad path[l++] = '0' + of->sc_unit;
195 1.37.10.2 ad path[l] = 0;
196 1.37.10.2 ad }
197 1.37.10.2 ad
198 1.37.10.2 ad strlcat(path, ":0", sizeof(path));
199 1.37.10.2 ad
200 1.37.10.2 ad if ((of->sc_ihandle = OF_open(path)) == -1) {
201 1.37.10.2 ad error = ENXIO;
202 1.37.10.2 ad goto bad1;
203 1.37.10.2 ad }
204 1.37.10.2 ad
205 1.37.10.2 ad /*
206 1.37.10.2 ad * Try to get characteristics of the disk.
207 1.37.10.2 ad */
208 1.37.10.2 ad of->max_transfer = OF_call_method_1("max-transfer",
209 1.37.10.2 ad of->sc_ihandle, 0);
210 1.37.10.2 ad if (of->max_transfer > MAXPHYS)
211 1.37.10.2 ad of->max_transfer = MAXPHYS;
212 1.37.10.2 ad
213 1.37.10.2 ad ofdisk_getdisklabel(dev);
214 1.37.10.2 ad }
215 1.37.10.2 ad
216 1.37.10.2 ad switch (fmt) {
217 1.37.10.2 ad case S_IFCHR:
218 1.37.10.2 ad of->sc_dk.dk_copenmask |= 1 << part;
219 1.37.10.2 ad break;
220 1.37.10.2 ad case S_IFBLK:
221 1.37.10.2 ad of->sc_dk.dk_bopenmask |= 1 << part;
222 1.37.10.2 ad break;
223 1.37.10.2 ad }
224 1.37.10.2 ad of->sc_dk.dk_openmask =
225 1.37.10.2 ad of->sc_dk.dk_copenmask | of->sc_dk.dk_bopenmask;
226 1.37.10.2 ad
227 1.37.10.2 ad
228 1.37.10.2 ad error = 0;
229 1.37.10.2 ad bad1:
230 1.37.10.2 ad mutex_exit(&of->sc_dk.dk_openlock);
231 1.37.10.2 ad return (error);
232 1.37.10.2 ad }
233 1.37.10.2 ad
234 1.37.10.2 ad int
235 1.37.10.2 ad ofdisk_close(dev_t dev, int flags, int fmt, struct lwp *l)
236 1.37.10.2 ad {
237 1.37.10.2 ad struct ofdisk_softc *of = ofdisk_cd.cd_devs[DISKUNIT(dev)];
238 1.37.10.2 ad
239 1.37.10.2 ad mutex_enter(&of->sc_dk.dk_openlock);
240 1.37.10.2 ad
241 1.37.10.2 ad switch (fmt) {
242 1.37.10.2 ad case S_IFCHR:
243 1.37.10.2 ad of->sc_dk.dk_copenmask &= ~(1 << DISKPART(dev));
244 1.37.10.2 ad break;
245 1.37.10.2 ad case S_IFBLK:
246 1.37.10.2 ad of->sc_dk.dk_bopenmask &= ~(1 << DISKPART(dev));
247 1.37.10.2 ad break;
248 1.37.10.2 ad }
249 1.37.10.2 ad of->sc_dk.dk_openmask = of->sc_dk.dk_copenmask | of->sc_dk.dk_bopenmask;
250 1.37.10.2 ad
251 1.37.10.2 ad #ifdef FIRMWORKSBUGS
252 1.37.10.2 ad /*
253 1.37.10.2 ad * This is a hack to get the firmware to flush its buffers.
254 1.37.10.2 ad */
255 1.37.10.2 ad OF_seek(of->sc_ihandle, 0);
256 1.37.10.2 ad #endif
257 1.37.10.2 ad if (!of->sc_dk.dk_openmask) {
258 1.37.10.2 ad OF_close(of->sc_ihandle);
259 1.37.10.2 ad of->sc_ihandle = 0;
260 1.37.10.2 ad }
261 1.37.10.2 ad
262 1.37.10.2 ad mutex_exit(&of->sc_dk.dk_openlock);
263 1.37.10.2 ad return 0;
264 1.37.10.2 ad }
265 1.37.10.2 ad
266 1.37.10.2 ad void
267 1.37.10.2 ad ofdisk_strategy(struct buf *bp)
268 1.37.10.2 ad {
269 1.37.10.2 ad struct ofdisk_softc *of = ofdisk_cd.cd_devs[DISKUNIT(bp->b_dev)];
270 1.37.10.2 ad struct partition *p;
271 1.37.10.2 ad u_quad_t off;
272 1.37.10.2 ad int read;
273 1.37.10.2 ad int (*OF_io)(int, void *, int);
274 1.37.10.2 ad daddr_t blkno = bp->b_blkno;
275 1.37.10.2 ad
276 1.37.10.2 ad bp->b_resid = 0;
277 1.37.10.2 ad if (bp->b_bcount == 0)
278 1.37.10.2 ad goto done;
279 1.37.10.2 ad
280 1.37.10.2 ad OF_io = bp->b_flags & B_READ ? OF_read :
281 1.37.10.2 ad (int(*)(int, void*, int))OF_write;
282 1.37.10.2 ad
283 1.37.10.2 ad if (DISKPART(bp->b_dev) != RAW_PART) {
284 1.37.10.2 ad if (bounds_check_with_label(&of->sc_dk, bp, 0) <= 0) {
285 1.37.10.2 ad bp->b_resid = bp->b_bcount;
286 1.37.10.2 ad goto done;
287 1.37.10.2 ad }
288 1.37.10.2 ad p = &of->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
289 1.37.10.2 ad blkno = bp->b_blkno + p->p_offset;
290 1.37.10.2 ad }
291 1.37.10.2 ad
292 1.37.10.2 ad disk_busy(&of->sc_dk);
293 1.37.10.2 ad
294 1.37.10.2 ad off = (u_quad_t)blkno * DEV_BSIZE;
295 1.37.10.2 ad read = -1;
296 1.37.10.2 ad do {
297 1.37.10.2 ad if (OF_seek(of->sc_ihandle, off) < 0)
298 1.37.10.2 ad break;
299 1.37.10.2 ad read = OF_io(of->sc_ihandle, bp->b_data, bp->b_bcount);
300 1.37.10.2 ad } while (read == -2);
301 1.37.10.2 ad
302 1.37.10.2 ad if (read < 0) {
303 1.37.10.2 ad bp->b_error = EIO;
304 1.37.10.2 ad bp->b_resid = bp->b_bcount;
305 1.37.10.2 ad } else
306 1.37.10.2 ad bp->b_resid = bp->b_bcount - read;
307 1.37.10.2 ad
308 1.37.10.2 ad disk_unbusy(&of->sc_dk, bp->b_bcount - bp->b_resid,
309 1.37.10.2 ad (bp->b_flags & B_READ));
310 1.37.10.2 ad
311 1.37.10.2 ad done:
312 1.37.10.2 ad biodone(bp);
313 1.37.10.2 ad }
314 1.37.10.2 ad
315 1.37.10.2 ad static void
316 1.37.10.2 ad ofminphys(struct buf *bp)
317 1.37.10.2 ad {
318 1.37.10.2 ad struct ofdisk_softc *of = ofdisk_cd.cd_devs[DISKUNIT(bp->b_dev)];
319 1.37.10.2 ad
320 1.37.10.2 ad if (bp->b_bcount > of->max_transfer)
321 1.37.10.2 ad bp->b_bcount = of->max_transfer;
322 1.37.10.2 ad }
323 1.37.10.2 ad
324 1.37.10.2 ad int
325 1.37.10.2 ad ofdisk_read(dev_t dev, struct uio *uio, int flags)
326 1.37.10.2 ad {
327 1.37.10.2 ad return physio(ofdisk_strategy, NULL, dev, B_READ, ofminphys, uio);
328 1.37.10.2 ad }
329 1.37.10.2 ad
330 1.37.10.2 ad int
331 1.37.10.2 ad ofdisk_write(dev_t dev, struct uio *uio, int flags)
332 1.37.10.2 ad {
333 1.37.10.2 ad return physio(ofdisk_strategy, NULL, dev, B_WRITE, ofminphys, uio);
334 1.37.10.2 ad }
335 1.37.10.2 ad
336 1.37.10.2 ad int
337 1.37.10.2 ad ofdisk_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
338 1.37.10.2 ad {
339 1.37.10.2 ad struct ofdisk_softc *of = ofdisk_cd.cd_devs[DISKUNIT(dev)];
340 1.37.10.2 ad int error;
341 1.37.10.2 ad #ifdef __HAVE_OLD_DISKLABEL
342 1.37.10.2 ad struct disklabel newlabel;
343 1.37.10.2 ad #endif
344 1.37.10.2 ad
345 1.37.10.2 ad switch (cmd) {
346 1.37.10.2 ad case DIOCGDINFO:
347 1.37.10.2 ad *(struct disklabel *)data = *of->sc_dk.dk_label;
348 1.37.10.2 ad return 0;
349 1.37.10.2 ad #ifdef __HAVE_OLD_DISKLABEL
350 1.37.10.2 ad case ODIOCGDINFO:
351 1.37.10.2 ad newlabel = *of->sc_dk.dk_label;
352 1.37.10.2 ad if (newlabel.d_npartitions > OLDMAXPARTITIONS)
353 1.37.10.2 ad return ENOTTY;
354 1.37.10.2 ad memcpy(data, &newlabel, sizeof (struct olddisklabel));
355 1.37.10.2 ad return 0;
356 1.37.10.2 ad #endif
357 1.37.10.2 ad
358 1.37.10.2 ad case DIOCGPART:
359 1.37.10.2 ad ((struct partinfo *)data)->disklab = of->sc_dk.dk_label;
360 1.37.10.2 ad ((struct partinfo *)data)->part =
361 1.37.10.2 ad &of->sc_dk.dk_label->d_partitions[DISKPART(dev)];
362 1.37.10.2 ad return 0;
363 1.37.10.2 ad
364 1.37.10.2 ad case DIOCWDINFO:
365 1.37.10.2 ad case DIOCSDINFO:
366 1.37.10.2 ad #ifdef __HAVE_OLD_DISKLABEL
367 1.37.10.2 ad case ODIOCWDINFO:
368 1.37.10.2 ad case ODIOCSDINFO:
369 1.37.10.2 ad #endif
370 1.37.10.2 ad {
371 1.37.10.2 ad struct disklabel *lp;
372 1.37.10.2 ad
373 1.37.10.2 ad #ifdef __HAVE_OLD_DISKLABEL
374 1.37.10.2 ad if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
375 1.37.10.2 ad memset(&newlabel, 0, sizeof newlabel);
376 1.37.10.2 ad memcpy(&newlabel, data, sizeof (struct olddisklabel));
377 1.37.10.2 ad lp = &newlabel;
378 1.37.10.2 ad } else
379 1.37.10.2 ad #endif
380 1.37.10.2 ad lp = (struct disklabel *)data;
381 1.37.10.2 ad
382 1.37.10.2 ad if ((flag & FWRITE) == 0)
383 1.37.10.2 ad return EBADF;
384 1.37.10.2 ad
385 1.37.10.2 ad mutex_enter(&of->sc_dk.dk_openlock);
386 1.37.10.2 ad
387 1.37.10.2 ad error = setdisklabel(of->sc_dk.dk_label,
388 1.37.10.2 ad lp, /*of->sc_dk.dk_openmask */0,
389 1.37.10.2 ad of->sc_dk.dk_cpulabel);
390 1.37.10.2 ad if (error == 0 && cmd == DIOCWDINFO
391 1.37.10.2 ad #ifdef __HAVE_OLD_DISKLABEL
392 1.37.10.2 ad || xfer == ODIOCWDINFO
393 1.37.10.2 ad #endif
394 1.37.10.2 ad )
395 1.37.10.2 ad error = writedisklabel(MAKEDISKDEV(major(dev),
396 1.37.10.2 ad DISKUNIT(dev), RAW_PART), ofdisk_strategy,
397 1.37.10.2 ad of->sc_dk.dk_label, of->sc_dk.dk_cpulabel);
398 1.37.10.2 ad
399 1.37.10.2 ad mutex_exit(&of->sc_dk.dk_openlock);
400 1.37.10.2 ad
401 1.37.10.2 ad return error;
402 1.37.10.2 ad }
403 1.37.10.2 ad
404 1.37.10.2 ad case DIOCGDEFLABEL:
405 1.37.10.2 ad ofdisk_getdefaultlabel(of, (struct disklabel *)data);
406 1.37.10.2 ad return 0;
407 1.37.10.2 ad #ifdef __HAVE_OLD_DISKLABEL
408 1.37.10.2 ad case DIOCGDEFLABEL:
409 1.37.10.2 ad ofdisk_getdefaultlabel(of, &newlabel);
410 1.37.10.2 ad if (newlabel.d_npartitions > OLDMAXPARTITIONS)
411 1.37.10.2 ad return ENOTTY;
412 1.37.10.2 ad memcpy(data, &newlabel, sizeof (struct olddisklabel));
413 1.37.10.2 ad return 0;
414 1.37.10.2 ad #endif
415 1.37.10.2 ad
416 1.37.10.2 ad case DIOCAWEDGE:
417 1.37.10.2 ad {
418 1.37.10.2 ad struct dkwedge_info *dkw = (void *) data;
419 1.37.10.2 ad
420 1.37.10.2 ad if (OFDISK_FLOPPY_P(of))
421 1.37.10.2 ad return (ENOTTY);
422 1.37.10.2 ad
423 1.37.10.2 ad if ((flag & FWRITE) == 0)
424 1.37.10.2 ad return (EBADF);
425 1.37.10.2 ad
426 1.37.10.2 ad /* If the ioctl happens here, the parent is us. */
427 1.37.10.2 ad strcpy(dkw->dkw_parent, of->sc_dev.dv_xname);
428 1.37.10.2 ad return (dkwedge_add(dkw));
429 1.37.10.2 ad }
430 1.37.10.2 ad
431 1.37.10.2 ad case DIOCDWEDGE:
432 1.37.10.2 ad {
433 1.37.10.2 ad struct dkwedge_info *dkw = (void *) data;
434 1.37.10.2 ad
435 1.37.10.2 ad if (OFDISK_FLOPPY_P(of))
436 1.37.10.2 ad return (ENOTTY);
437 1.37.10.2 ad
438 1.37.10.2 ad if ((flag & FWRITE) == 0)
439 1.37.10.2 ad return (EBADF);
440 1.37.10.2 ad
441 1.37.10.2 ad /* If the ioctl happens here, the parent is us. */
442 1.37.10.2 ad strcpy(dkw->dkw_parent, of->sc_dev.dv_xname);
443 1.37.10.2 ad return (dkwedge_del(dkw));
444 1.37.10.2 ad }
445 1.37.10.2 ad
446 1.37.10.2 ad case DIOCLWEDGES:
447 1.37.10.2 ad {
448 1.37.10.2 ad struct dkwedge_list *dkwl = (void *) data;
449 1.37.10.2 ad
450 1.37.10.2 ad if (OFDISK_FLOPPY_P(of))
451 1.37.10.2 ad return (ENOTTY);
452 1.37.10.2 ad
453 1.37.10.2 ad return (dkwedge_list(&of->sc_dk, dkwl, l));
454 1.37.10.2 ad }
455 1.37.10.2 ad
456 1.37.10.2 ad default:
457 1.37.10.2 ad return ENOTTY;
458 1.37.10.2 ad }
459 1.37.10.2 ad }
460 1.37.10.2 ad
461 1.37.10.2 ad int
462 1.37.10.2 ad ofdisk_dump(dev_t dev, daddr_t blkno, void *va, size_t size)
463 1.37.10.2 ad {
464 1.37.10.2 ad return EINVAL;
465 1.37.10.2 ad }
466 1.37.10.2 ad
467 1.37.10.2 ad int
468 1.37.10.2 ad ofdisk_size(dev_t dev)
469 1.37.10.2 ad {
470 1.37.10.2 ad struct ofdisk_softc *of;
471 1.37.10.2 ad struct disklabel *lp;
472 1.37.10.2 ad int size, part, omask, unit;
473 1.37.10.2 ad
474 1.37.10.2 ad unit = DISKUNIT(dev);
475 1.37.10.2 ad if (unit >= ofdisk_cd.cd_ndevs ||
476 1.37.10.2 ad (of = ofdisk_cd.cd_devs[unit]) == NULL)
477 1.37.10.2 ad return -1;
478 1.37.10.2 ad
479 1.37.10.2 ad part = DISKPART(dev);
480 1.37.10.2 ad omask = of->sc_dk.dk_openmask & (1 << part);
481 1.37.10.2 ad lp = of->sc_dk.dk_label;
482 1.37.10.2 ad
483 1.37.10.2 ad if (omask == 0 && ofdisk_open(dev, 0, S_IFBLK, curlwp) != 0)
484 1.37.10.2 ad return -1;
485 1.37.10.2 ad
486 1.37.10.2 ad if (lp->d_partitions[part].p_fstype != FS_SWAP)
487 1.37.10.2 ad size = -1;
488 1.37.10.2 ad else
489 1.37.10.2 ad size = lp->d_partitions[part].p_size *
490 1.37.10.2 ad (lp->d_secsize / DEV_BSIZE);
491 1.37.10.2 ad
492 1.37.10.2 ad if (omask == 0 && ofdisk_close(dev, 0, S_IFBLK, curlwp) != 0)
493 1.37.10.2 ad return -1;
494 1.37.10.2 ad
495 1.37.10.2 ad return size;
496 1.37.10.2 ad }
497 1.37.10.2 ad
498 1.37.10.2 ad void
499 1.37.10.2 ad ofdisk_getdefaultlabel(struct ofdisk_softc *of, struct disklabel *lp)
500 1.37.10.2 ad {
501 1.37.10.2 ad
502 1.37.10.2 ad memset(lp, 0, sizeof *lp);
503 1.37.10.2 ad
504 1.37.10.2 ad /*
505 1.37.10.2 ad * XXX Firmware bug? Asking for block size gives a
506 1.37.10.2 ad * XXX ridiculous number! So we use what the boot program
507 1.37.10.2 ad * XXX uses.
508 1.37.10.2 ad */
509 1.37.10.2 ad lp->d_secsize = DEV_BSIZE;
510 1.37.10.2 ad
511 1.37.10.2 ad lp->d_secperunit = OF_call_method_1("#blocks",
512 1.37.10.2 ad of->sc_ihandle, 0);
513 1.37.10.2 ad if (lp->d_secperunit == (u_int32_t)-1)
514 1.37.10.2 ad lp->d_secperunit = 0x7fffffff;
515 1.37.10.2 ad
516 1.37.10.2 ad lp->d_secpercyl = 1;
517 1.37.10.2 ad lp->d_nsectors = 1;
518 1.37.10.2 ad lp->d_ntracks = 1;
519 1.37.10.2 ad lp->d_ncylinders = lp->d_secperunit;
520 1.37.10.2 ad
521 1.37.10.2 ad lp->d_partitions[RAW_PART].p_offset = 0;
522 1.37.10.2 ad lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
523 1.37.10.2 ad lp->d_npartitions = RAW_PART + 1;
524 1.37.10.2 ad
525 1.37.10.2 ad lp->d_magic = DISKMAGIC;
526 1.37.10.2 ad lp->d_magic2 = DISKMAGIC;
527 1.37.10.2 ad lp->d_checksum = dkcksum(lp);
528 1.37.10.2 ad }
529 1.37.10.2 ad
530 1.37.10.2 ad void
531 1.37.10.2 ad ofdisk_getdisklabel(dev)
532 1.37.10.2 ad dev_t dev;
533 1.37.10.2 ad {
534 1.37.10.2 ad int unit = DISKUNIT(dev);
535 1.37.10.2 ad struct ofdisk_softc *of = ofdisk_cd.cd_devs[unit];
536 1.37.10.2 ad struct disklabel *lp = of->sc_dk.dk_label;
537 1.37.10.2 ad const char *errmes;
538 1.37.10.2 ad int l;
539 1.37.10.2 ad
540 1.37.10.2 ad ofdisk_getdefaultlabel(of, lp);
541 1.37.10.2 ad
542 1.37.10.2 ad /*
543 1.37.10.2 ad * Don't read the disklabel on a floppy; simply
544 1.37.10.2 ad * assign all partitions the same size/offset as
545 1.37.10.2 ad * RAW_PART. (This is essentially what the ISA
546 1.37.10.2 ad * floppy driver does, but we don't deal with
547 1.37.10.2 ad * density stuff.)
548 1.37.10.2 ad */
549 1.37.10.2 ad if (OFDISK_FLOPPY_P(of)) {
550 1.37.10.2 ad lp->d_npartitions = MAXPARTITIONS;
551 1.37.10.2 ad for (l = 0; l < lp->d_npartitions; l++) {
552 1.37.10.2 ad if (l == RAW_PART)
553 1.37.10.2 ad continue;
554 1.37.10.2 ad /* struct copy */
555 1.37.10.2 ad lp->d_partitions[l] =
556 1.37.10.2 ad lp->d_partitions[RAW_PART];
557 1.37.10.2 ad }
558 1.37.10.2 ad lp->d_checksum = dkcksum(lp);
559 1.37.10.2 ad } else {
560 1.37.10.2 ad errmes = readdisklabel(MAKEDISKDEV(major(dev),
561 1.37.10.2 ad unit, RAW_PART), ofdisk_strategy, lp,
562 1.37.10.2 ad of->sc_dk.dk_cpulabel);
563 1.37.10.2 ad if (errmes != NULL)
564 1.37.10.2 ad printf("%s: %s\n", of->sc_dev.dv_xname, errmes);
565 1.37.10.2 ad }
566 1.37.10.2 ad }
567