fd.c revision 1.70 1 1.70 pk /* $NetBSD: fd.c,v 1.70 2000/01/17 16:57:15 pk Exp $ */
2 1.1 pk
3 1.1 pk /*-
4 1.64 mycroft * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.
5 1.1 pk * Copyright (c) 1995 Paul Kranenburg.
6 1.1 pk * Copyright (c) 1990 The Regents of the University of California.
7 1.1 pk * All rights reserved.
8 1.1 pk *
9 1.1 pk * This code is derived from software contributed to Berkeley by
10 1.1 pk * Don Ahn.
11 1.1 pk *
12 1.1 pk * Redistribution and use in source and binary forms, with or without
13 1.1 pk * modification, are permitted provided that the following conditions
14 1.1 pk * are met:
15 1.1 pk * 1. Redistributions of source code must retain the above copyright
16 1.1 pk * notice, this list of conditions and the following disclaimer.
17 1.1 pk * 2. Redistributions in binary form must reproduce the above copyright
18 1.1 pk * notice, this list of conditions and the following disclaimer in the
19 1.1 pk * documentation and/or other materials provided with the distribution.
20 1.1 pk * 3. All advertising materials mentioning features or use of this software
21 1.1 pk * must display the following acknowledgement:
22 1.1 pk * This product includes software developed by the University of
23 1.1 pk * California, Berkeley and its contributors.
24 1.1 pk * 4. Neither the name of the University nor the names of its contributors
25 1.1 pk * may be used to endorse or promote products derived from this software
26 1.1 pk * without specific prior written permission.
27 1.1 pk *
28 1.1 pk * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 1.1 pk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 1.1 pk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 1.1 pk * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 1.1 pk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 1.1 pk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 1.1 pk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 1.1 pk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 1.1 pk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 1.1 pk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 1.1 pk * SUCH DAMAGE.
39 1.1 pk *
40 1.1 pk * @(#)fd.c 7.4 (Berkeley) 5/25/91
41 1.1 pk */
42 1.57 mrg
43 1.62 jonathan #include "opt_ddb.h"
44 1.65 jonathan #include "opt_md.h"
45 1.1 pk
46 1.1 pk #include <sys/param.h>
47 1.1 pk #include <sys/systm.h>
48 1.1 pk #include <sys/kernel.h>
49 1.1 pk #include <sys/file.h>
50 1.1 pk #include <sys/ioctl.h>
51 1.1 pk #include <sys/device.h>
52 1.1 pk #include <sys/disklabel.h>
53 1.1 pk #include <sys/dkstat.h>
54 1.1 pk #include <sys/disk.h>
55 1.42 pk #include <sys/fdio.h>
56 1.1 pk #include <sys/buf.h>
57 1.42 pk #include <sys/malloc.h>
58 1.42 pk #include <sys/proc.h>
59 1.1 pk #include <sys/uio.h>
60 1.19 thorpej #include <sys/stat.h>
61 1.1 pk #include <sys/syslog.h>
62 1.1 pk #include <sys/queue.h>
63 1.30 christos #include <sys/conf.h>
64 1.24 christos
65 1.24 christos #include <dev/cons.h>
66 1.56 mrg
67 1.56 mrg #include <vm/vm.h>
68 1.67 mrg
69 1.56 mrg #include <uvm/uvm_extern.h>
70 1.1 pk
71 1.1 pk #include <machine/cpu.h>
72 1.1 pk #include <machine/autoconf.h>
73 1.30 christos #include <machine/conf.h>
74 1.30 christos
75 1.2 pk #include <sparc/sparc/auxreg.h>
76 1.1 pk #include <sparc/dev/fdreg.h>
77 1.2 pk #include <sparc/dev/fdvar.h>
78 1.1 pk
79 1.1 pk #define FDUNIT(dev) (minor(dev) / 8)
80 1.1 pk #define FDTYPE(dev) (minor(dev) % 8)
81 1.1 pk
82 1.42 pk /* XXX misuse a flag to identify format operation */
83 1.42 pk #define B_FORMAT B_XXX
84 1.1 pk #define b_cylin b_resid
85 1.1 pk
86 1.2 pk #define FD_DEBUG
87 1.2 pk #ifdef FD_DEBUG
88 1.2 pk int fdc_debug = 0;
89 1.2 pk #endif
90 1.2 pk
91 1.1 pk enum fdc_state {
92 1.1 pk DEVIDLE = 0,
93 1.1 pk MOTORWAIT,
94 1.1 pk DOSEEK,
95 1.1 pk SEEKWAIT,
96 1.1 pk SEEKTIMEDOUT,
97 1.1 pk SEEKCOMPLETE,
98 1.1 pk DOIO,
99 1.2 pk IOCOMPLETE,
100 1.1 pk IOTIMEDOUT,
101 1.1 pk DORESET,
102 1.1 pk RESETCOMPLETE,
103 1.1 pk RESETTIMEDOUT,
104 1.1 pk DORECAL,
105 1.1 pk RECALWAIT,
106 1.1 pk RECALTIMEDOUT,
107 1.1 pk RECALCOMPLETE,
108 1.1 pk };
109 1.1 pk
110 1.1 pk /* software state, per controller */
111 1.1 pk struct fdc_softc {
112 1.14 pk struct device sc_dev; /* boilerplate */
113 1.58 pk bus_space_tag_t sc_bustag;
114 1.70 pk
115 1.1 pk struct fd_softc *sc_fd[4]; /* pointers to children */
116 1.1 pk TAILQ_HEAD(drivehead, fd_softc) sc_drives;
117 1.1 pk enum fdc_state sc_state;
118 1.2 pk int sc_flags;
119 1.2 pk #define FDC_82077 0x01
120 1.2 pk #define FDC_NEEDHEADSETTLE 0x02
121 1.2 pk #define FDC_EIS 0x04
122 1.2 pk int sc_errors; /* number of retries so far */
123 1.6 pk int sc_overruns; /* number of DMA overruns */
124 1.2 pk int sc_cfg; /* current configuration */
125 1.2 pk struct fdcio sc_io;
126 1.70 pk #define sc_handle sc_io.fdcio_handle
127 1.2 pk #define sc_reg_msr sc_io.fdcio_reg_msr
128 1.2 pk #define sc_reg_fifo sc_io.fdcio_reg_fifo
129 1.2 pk #define sc_reg_dor sc_io.fdcio_reg_dor
130 1.2 pk #define sc_reg_drs sc_io.fdcio_reg_msr
131 1.2 pk #define sc_istate sc_io.fdcio_istate
132 1.2 pk #define sc_data sc_io.fdcio_data
133 1.2 pk #define sc_tc sc_io.fdcio_tc
134 1.2 pk #define sc_nstat sc_io.fdcio_nstat
135 1.2 pk #define sc_status sc_io.fdcio_status
136 1.3 pk #define sc_intrcnt sc_io.fdcio_intrcnt
137 1.1 pk };
138 1.1 pk
139 1.2 pk #ifndef FDC_C_HANDLER
140 1.2 pk extern struct fdcio *fdciop;
141 1.2 pk #endif
142 1.2 pk
143 1.1 pk /* controller driver configuration */
144 1.58 pk int fdcmatch_mainbus __P((struct device *, struct cfdata *, void *));
145 1.58 pk int fdcmatch_obio __P((struct device *, struct cfdata *, void *));
146 1.58 pk void fdcattach_mainbus __P((struct device *, struct device *, void *));
147 1.58 pk void fdcattach_obio __P((struct device *, struct device *, void *));
148 1.1 pk
149 1.69 pk void fdcattach __P((struct fdc_softc *, int));
150 1.58 pk
151 1.58 pk struct cfattach fdc_mainbus_ca = {
152 1.58 pk sizeof(struct fdc_softc), fdcmatch_mainbus, fdcattach_mainbus
153 1.58 pk };
154 1.58 pk struct cfattach fdc_obio_ca = {
155 1.58 pk sizeof(struct fdc_softc), fdcmatch_obio, fdcattach_obio
156 1.26 thorpej };
157 1.24 christos
158 1.24 christos __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
159 1.24 christos
160 1.1 pk /*
161 1.1 pk * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
162 1.1 pk * we tell them apart.
163 1.1 pk */
164 1.1 pk struct fd_type {
165 1.1 pk int sectrac; /* sectors per track */
166 1.1 pk int heads; /* number of heads */
167 1.1 pk int seccyl; /* sectors per cylinder */
168 1.1 pk int secsize; /* size code for sectors */
169 1.1 pk int datalen; /* data len when secsize = 0 */
170 1.1 pk int steprate; /* step rate and head unload time */
171 1.1 pk int gap1; /* gap len between sectors */
172 1.1 pk int gap2; /* formatting gap */
173 1.49 pk int cylinders; /* total num of cylinders */
174 1.1 pk int size; /* size of disk in sectors */
175 1.1 pk int step; /* steps per cylinder */
176 1.1 pk int rate; /* transfer speed code */
177 1.42 pk int fillbyte; /* format fill byte */
178 1.42 pk int interleave; /* interleave factor (formatting) */
179 1.1 pk char *name;
180 1.1 pk };
181 1.1 pk
182 1.1 pk /* The order of entries in the following table is important -- BEWARE! */
183 1.1 pk struct fd_type fd_types[] = {
184 1.42 pk { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */
185 1.42 pk { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5" 720kB diskette */
186 1.42 pk { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */
187 1.53 pk { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS,0xf6,1, "1.2MB/NEC" } /* 1.2 MB japanese format */
188 1.1 pk };
189 1.1 pk
190 1.1 pk /* software state, per disk (with up to 4 disks per ctlr) */
191 1.1 pk struct fd_softc {
192 1.16 thorpej struct device sc_dv; /* generic device info */
193 1.16 thorpej struct disk sc_dk; /* generic disk info */
194 1.1 pk
195 1.1 pk struct fd_type *sc_deftype; /* default type descriptor */
196 1.1 pk struct fd_type *sc_type; /* current type descriptor */
197 1.1 pk
198 1.1 pk daddr_t sc_blkno; /* starting block number */
199 1.1 pk int sc_bcount; /* byte count left */
200 1.1 pk int sc_skip; /* bytes already transferred */
201 1.1 pk int sc_nblks; /* number of blocks currently tranferring */
202 1.1 pk int sc_nbytes; /* number of bytes currently tranferring */
203 1.1 pk
204 1.1 pk int sc_drive; /* physical unit number */
205 1.1 pk int sc_flags;
206 1.1 pk #define FD_OPEN 0x01 /* it's open */
207 1.1 pk #define FD_MOTOR 0x02 /* motor should be on */
208 1.1 pk #define FD_MOTOR_WAIT 0x04 /* motor coming up */
209 1.1 pk int sc_cylin; /* where we think the head is */
210 1.42 pk int sc_opts; /* user-set options */
211 1.1 pk
212 1.20 thorpej void *sc_sdhook; /* shutdownhook cookie */
213 1.20 thorpej
214 1.1 pk TAILQ_ENTRY(fd_softc) sc_drivechain;
215 1.1 pk int sc_ops; /* I/O ops since last switch */
216 1.1 pk struct buf sc_q; /* head of buf chain */
217 1.1 pk };
218 1.1 pk
219 1.1 pk /* floppy driver configuration */
220 1.44 pk int fdmatch __P((struct device *, struct cfdata *, void *));
221 1.1 pk void fdattach __P((struct device *, struct device *, void *));
222 1.1 pk
223 1.26 thorpej struct cfattach fd_ca = {
224 1.26 thorpej sizeof(struct fd_softc), fdmatch, fdattach
225 1.26 thorpej };
226 1.26 thorpej
227 1.55 thorpej extern struct cfdriver fd_cd;
228 1.1 pk
229 1.19 thorpej void fdgetdisklabel __P((dev_t));
230 1.1 pk int fd_get_parms __P((struct fd_softc *));
231 1.1 pk void fdstrategy __P((struct buf *));
232 1.1 pk void fdstart __P((struct fd_softc *));
233 1.37 cgd int fdprint __P((void *, const char *));
234 1.1 pk
235 1.1 pk struct dkdriver fddkdriver = { fdstrategy };
236 1.1 pk
237 1.1 pk struct fd_type *fd_nvtotype __P((char *, int, int));
238 1.12 pk void fd_set_motor __P((struct fdc_softc *fdc));
239 1.1 pk void fd_motor_off __P((void *arg));
240 1.1 pk void fd_motor_on __P((void *arg));
241 1.1 pk int fdcresult __P((struct fdc_softc *fdc));
242 1.1 pk int out_fdc __P((struct fdc_softc *fdc, u_char x));
243 1.1 pk void fdcstart __P((struct fdc_softc *fdc));
244 1.1 pk void fdcstatus __P((struct device *dv, int n, char *s));
245 1.12 pk void fdc_reset __P((struct fdc_softc *fdc));
246 1.1 pk void fdctimeout __P((void *arg));
247 1.1 pk void fdcpseudointr __P((void *arg));
248 1.2 pk #ifdef FDC_C_HANDLER
249 1.58 pk int fdchwintr __P((void *));
250 1.2 pk #else
251 1.2 pk void fdchwintr __P((void));
252 1.2 pk #endif
253 1.58 pk int fdcswintr __P((void *));
254 1.42 pk int fdcstate __P((struct fdc_softc *));
255 1.1 pk void fdcretry __P((struct fdc_softc *fdc));
256 1.1 pk void fdfinish __P((struct fd_softc *fd, struct buf *bp));
257 1.42 pk int fdformat __P((dev_t, struct ne7_fd_formb *, struct proc *));
258 1.50 pk void fd_do_eject __P((struct fd_softc *));
259 1.19 thorpej void fd_mountroot_hook __P((struct device *));
260 1.70 pk static int fdconf __P((struct fdc_softc *));
261 1.70 pk static void establish_chip_type __P((
262 1.70 pk struct fdc_softc *,
263 1.70 pk bus_space_tag_t,
264 1.70 pk bus_type_t,
265 1.70 pk bus_addr_t,
266 1.70 pk bus_size_t,
267 1.70 pk bus_space_handle_t));
268 1.70 pk
269 1.1 pk
270 1.2 pk #if PIL_FDSOFT == 4
271 1.1 pk #define IE_FDSOFT IE_L4
272 1.2 pk #else
273 1.2 pk #error 4
274 1.2 pk #endif
275 1.1 pk
276 1.42 pk #ifdef FDC_C_HANDLER
277 1.42 pk #if defined(SUN4M)
278 1.42 pk #define FD_SET_SWINTR do { \
279 1.42 pk if (CPU_ISSUN4M) \
280 1.42 pk raise(0, PIL_FDSOFT); \
281 1.42 pk else \
282 1.42 pk ienab_bis(IE_L4); \
283 1.42 pk } while(0)
284 1.42 pk #else
285 1.42 pk #define AUDIO_SET_SWINTR ienab_bis(IE_FDSOFT)
286 1.42 pk #endif /* defined(SUN4M) */
287 1.42 pk #endif /* FDC_C_HANDLER */
288 1.42 pk
289 1.23 pk #define OBP_FDNAME (CPU_ISSUN4M ? "SUNW,fdtwo" : "fd")
290 1.10 pk
291 1.1 pk int
292 1.58 pk fdcmatch_mainbus(parent, match, aux)
293 1.1 pk struct device *parent;
294 1.44 pk struct cfdata *match;
295 1.44 pk void *aux;
296 1.1 pk {
297 1.58 pk struct mainbus_attach_args *ma = aux;
298 1.1 pk
299 1.23 pk /*
300 1.58 pk * Floppy controller is on mainbus on sun4c.
301 1.23 pk */
302 1.58 pk if (!CPU_ISSUN4C)
303 1.58 pk return (0);
304 1.58 pk
305 1.58 pk /* sun4c PROMs call the controller "fd" */
306 1.58 pk if (strcmp("fd", ma->ma_name) != 0)
307 1.23 pk return (0);
308 1.23 pk
309 1.60 pk return (bus_space_probe(ma->ma_bustag,
310 1.60 pk ma->ma_iospace,
311 1.60 pk ma->ma_paddr,
312 1.60 pk 1, /* probe size */
313 1.60 pk 0, /* offset */
314 1.60 pk 0, /* flags */
315 1.60 pk NULL, NULL));
316 1.58 pk }
317 1.58 pk
318 1.58 pk int
319 1.58 pk fdcmatch_obio(parent, match, aux)
320 1.58 pk struct device *parent;
321 1.58 pk struct cfdata *match;
322 1.58 pk void *aux;
323 1.58 pk {
324 1.58 pk union obio_attach_args *uoba = aux;
325 1.58 pk struct sbus_attach_args *sa;
326 1.23 pk
327 1.23 pk /*
328 1.23 pk * Floppy controller is on obio on sun4m.
329 1.23 pk */
330 1.58 pk if (uoba->uoba_isobio4 != 0)
331 1.23 pk return (0);
332 1.23 pk
333 1.58 pk sa = &uoba->uoba_sbus;
334 1.58 pk
335 1.58 pk /* sun4m PROMs call the controller "SUNW,fdtwo" */
336 1.58 pk if (strcmp("SUNW,fdtwo", sa->sa_name) != 0)
337 1.1 pk return (0);
338 1.23 pk
339 1.60 pk return (bus_space_probe(sa->sa_bustag, sa->sa_slot, sa->sa_offset,
340 1.60 pk 1, /* probe size */
341 1.60 pk 0, /* offset */
342 1.60 pk 0, /* flags */
343 1.60 pk NULL, NULL));
344 1.1 pk }
345 1.1 pk
346 1.70 pk static void
347 1.70 pk establish_chip_type(fdc, tag, type, addr, size, handle)
348 1.70 pk struct fdc_softc *fdc;
349 1.70 pk bus_space_tag_t tag;
350 1.70 pk bus_type_t type;
351 1.70 pk bus_addr_t addr;
352 1.70 pk bus_size_t size;
353 1.70 pk bus_space_handle_t handle;
354 1.70 pk {
355 1.70 pk u_int8_t v;
356 1.70 pk
357 1.70 pk /*
358 1.70 pk * This hack from Chris Torek: apparently DOR really
359 1.70 pk * addresses MSR/DRS on a 82072.
360 1.70 pk * We used to rely on the VERSION command to tell the
361 1.70 pk * difference (which did not work).
362 1.70 pk */
363 1.70 pk
364 1.70 pk /* First, check the size of the register bank */
365 1.70 pk if (size < 8)
366 1.70 pk /* It isn't a 82077 */
367 1.70 pk return;
368 1.70 pk
369 1.70 pk /* Then probe the DOR register offset */
370 1.70 pk if (bus_space_probe(tag, type, addr,
371 1.70 pk 1, /* probe size */
372 1.70 pk FDREG77_DOR, /* offset */
373 1.70 pk 0, /* flags */
374 1.70 pk NULL, NULL) == 0) {
375 1.70 pk
376 1.70 pk /* It isn't a 82077 */
377 1.70 pk return;
378 1.70 pk }
379 1.70 pk
380 1.70 pk v = bus_space_read_1(tag, handle, FDREG77_DOR);
381 1.70 pk if (v == NE7_RQM) {
382 1.70 pk /*
383 1.70 pk * Value in DOR looks like it's really MSR
384 1.70 pk */
385 1.70 pk bus_space_write_1(tag, handle, FDREG77_DOR, FDC_250KBPS);
386 1.70 pk v = bus_space_read_1(tag, handle, FDREG77_DOR);
387 1.70 pk if (v == NE7_RQM) {
388 1.70 pk /*
389 1.70 pk * The value in the DOR didn't stick;
390 1.70 pk * it isn't a 82077
391 1.70 pk */
392 1.70 pk return;
393 1.70 pk }
394 1.70 pk }
395 1.70 pk
396 1.70 pk fdc->sc_flags |= FDC_82077;
397 1.70 pk }
398 1.70 pk
399 1.1 pk /*
400 1.1 pk * Arguments passed between fdcattach and fdprobe.
401 1.1 pk */
402 1.1 pk struct fdc_attach_args {
403 1.1 pk int fa_drive;
404 1.1 pk struct fd_type *fa_deftype;
405 1.1 pk };
406 1.1 pk
407 1.1 pk /*
408 1.1 pk * Print the location of a disk drive (called just before attaching the
409 1.1 pk * the drive). If `fdc' is not NULL, the drive was found but was not
410 1.1 pk * in the system config file; print the drive name as well.
411 1.1 pk * Return QUIET (config_find ignores this if the device was configured) to
412 1.1 pk * avoid printing `fdN not configured' messages.
413 1.1 pk */
414 1.1 pk int
415 1.1 pk fdprint(aux, fdc)
416 1.1 pk void *aux;
417 1.37 cgd const char *fdc;
418 1.1 pk {
419 1.1 pk register struct fdc_attach_args *fa = aux;
420 1.1 pk
421 1.1 pk if (!fdc)
422 1.39 christos printf(" drive %d", fa->fa_drive);
423 1.42 pk return (QUIET);
424 1.1 pk }
425 1.1 pk
426 1.70 pk static int
427 1.1 pk fdconf(fdc)
428 1.1 pk struct fdc_softc *fdc;
429 1.1 pk {
430 1.1 pk int vroom;
431 1.1 pk
432 1.1 pk if (out_fdc(fdc, NE7CMD_DUMPREG) || fdcresult(fdc) != 10)
433 1.70 pk return (-1);
434 1.1 pk
435 1.1 pk /*
436 1.1 pk * dumpreg[7] seems to be a motor-off timeout; set it to whatever
437 1.1 pk * the PROM thinks is appropriate.
438 1.1 pk */
439 1.1 pk if ((vroom = fdc->sc_status[7]) == 0)
440 1.1 pk vroom = 0x64;
441 1.1 pk
442 1.1 pk /* Configure controller to use FIFO and Implied Seek */
443 1.1 pk out_fdc(fdc, NE7CMD_CFG);
444 1.1 pk out_fdc(fdc, vroom);
445 1.2 pk out_fdc(fdc, fdc->sc_cfg);
446 1.1 pk out_fdc(fdc, 0); /* PRETRK */
447 1.70 pk /* No result phase for the NE7CMD_CFG command */
448 1.70 pk
449 1.70 pk if ((fdc->sc_flags & FDC_82077) != 0) {
450 1.70 pk /* Lock configuration across soft resets. */
451 1.70 pk out_fdc(fdc, NE7CMD_LOCK | CFG_LOCK);
452 1.70 pk if (fdcresult(fdc) != 1) {
453 1.70 pk #ifdef DEBUG
454 1.70 pk printf("fdconf: CFGLOCK failed");
455 1.70 pk #endif
456 1.70 pk return (-1);
457 1.70 pk }
458 1.70 pk }
459 1.70 pk
460 1.70 pk return (0);
461 1.70 pk #if 0
462 1.70 pk if (out_fdc(fdc, NE7CMD_VERSION) == 0 &&
463 1.70 pk fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x90) {
464 1.70 pk if (fdc_debug)
465 1.70 pk printf("[version cmd]");
466 1.70 pk }
467 1.70 pk #endif
468 1.1 pk }
469 1.1 pk
470 1.58 pk /*
471 1.58 pk * Controller and drives are represented by one and the same
472 1.58 pk * Openprom node, so we can as well check for the floppy boots here.
473 1.58 pk */
474 1.58 pk
475 1.58 pk void
476 1.58 pk fdcattach_mainbus(parent, self, aux)
477 1.58 pk struct device *parent, *self;
478 1.58 pk void *aux;
479 1.58 pk {
480 1.58 pk struct fdc_softc *fdc = (void *)self;
481 1.58 pk struct mainbus_attach_args *ma = aux;
482 1.58 pk
483 1.58 pk fdc->sc_bustag = ma->ma_bustag;
484 1.58 pk
485 1.59 pk if (ma->ma_promvaddr != 0)
486 1.70 pk fdc->sc_handle = (bus_space_handle_t)ma->ma_promvaddr;
487 1.59 pk else {
488 1.60 pk if (bus_space_map2(
489 1.59 pk ma->ma_bustag,
490 1.59 pk ma->ma_iospace,
491 1.60 pk ma->ma_paddr,
492 1.59 pk ma->ma_size,
493 1.59 pk BUS_SPACE_MAP_LINEAR,
494 1.59 pk 0,
495 1.70 pk &fdc->sc_handle) != 0) {
496 1.59 pk printf("%s: cannot map registers\n", self->dv_xname);
497 1.59 pk return;
498 1.59 pk }
499 1.59 pk }
500 1.58 pk
501 1.70 pk establish_chip_type(fdc,
502 1.70 pk ma->ma_bustag,
503 1.70 pk ma->ma_iospace,
504 1.70 pk ma->ma_paddr,
505 1.70 pk ma->ma_size,
506 1.70 pk fdc->sc_handle);
507 1.70 pk
508 1.69 pk fdcattach(fdc, ma->ma_pri);
509 1.58 pk }
510 1.58 pk
511 1.1 pk void
512 1.58 pk fdcattach_obio(parent, self, aux)
513 1.1 pk struct device *parent, *self;
514 1.1 pk void *aux;
515 1.1 pk {
516 1.1 pk struct fdc_softc *fdc = (void *)self;
517 1.58 pk union obio_attach_args *uoba = aux;
518 1.58 pk struct sbus_attach_args *sa = &uoba->uoba_sbus;
519 1.58 pk
520 1.58 pk fdc->sc_bustag = sa->sa_bustag;
521 1.58 pk
522 1.63 pk if (sa->sa_npromvaddrs != 0)
523 1.70 pk fdc->sc_handle = (bus_space_handle_t)sa->sa_promvaddrs[0];
524 1.58 pk else {
525 1.58 pk if (sbus_bus_map(sa->sa_bustag, sa->sa_slot,
526 1.58 pk sa->sa_offset,
527 1.58 pk sa->sa_size,
528 1.58 pk BUS_SPACE_MAP_LINEAR,
529 1.58 pk 0,
530 1.70 pk &fdc->sc_handle) != 0) {
531 1.58 pk printf("%s: cannot map control registers\n",
532 1.58 pk self->dv_xname);
533 1.58 pk return;
534 1.58 pk }
535 1.58 pk }
536 1.58 pk
537 1.70 pk establish_chip_type(fdc,
538 1.70 pk sa->sa_bustag,
539 1.70 pk sa->sa_slot,
540 1.70 pk sa->sa_offset,
541 1.70 pk sa->sa_size,
542 1.70 pk fdc->sc_handle);
543 1.70 pk
544 1.68 pk if (sa->sa_nintr != 0)
545 1.69 pk fdcattach(fdc, sa->sa_pri);
546 1.58 pk }
547 1.58 pk
548 1.58 pk void
549 1.69 pk fdcattach(fdc, pri)
550 1.58 pk struct fdc_softc *fdc;
551 1.24 christos int pri;
552 1.58 pk {
553 1.58 pk struct fdc_attach_args fa;
554 1.8 pk char code;
555 1.1 pk
556 1.2 pk fdc->sc_state = DEVIDLE;
557 1.2 pk fdc->sc_istate = ISTATE_IDLE;
558 1.2 pk fdc->sc_flags |= FDC_EIS;
559 1.2 pk TAILQ_INIT(&fdc->sc_drives);
560 1.2 pk
561 1.70 pk if ((fdc->sc_flags & FDC_82077) != 0) {
562 1.70 pk fdc->sc_reg_msr = FDREG77_MSR;
563 1.70 pk fdc->sc_reg_fifo = FDREG77_FIFO;
564 1.70 pk fdc->sc_reg_dor = FDREG77_DOR;
565 1.70 pk code = '7';
566 1.70 pk } else {
567 1.70 pk fdc->sc_reg_msr = FDREG72_MSR;
568 1.70 pk fdc->sc_reg_fifo = FDREG72_FIFO;
569 1.70 pk fdc->sc_reg_dor = 0;
570 1.70 pk code = '2';
571 1.70 pk }
572 1.70 pk
573 1.70 pk printf(" softpri %d: chip 8207%c\n", PIL_FDSOFT, code);
574 1.70 pk
575 1.70 pk /*
576 1.70 pk * Configure controller; enable FIFO, Implied seek, no POLL mode?.
577 1.70 pk * Note: CFG_EFIFO is active-low, initial threshold value: 8
578 1.70 pk */
579 1.70 pk fdc->sc_cfg = CFG_EIS|/*CFG_EFIFO|*/CFG_POLL|(8 & CFG_THRHLD_MASK);
580 1.70 pk if (fdconf(fdc) != 0) {
581 1.70 pk printf("%s: no drives attached\n", fdc->sc_dev.dv_xname);
582 1.70 pk return;
583 1.70 pk }
584 1.70 pk
585 1.2 pk #ifdef FDC_C_HANDLER
586 1.58 pk (void)bus_intr_establish(fdc->sc_bustag, pri, 0,
587 1.58 pk fdchwintr, fdc);
588 1.2 pk #else
589 1.2 pk fdciop = &fdc->sc_io;
590 1.58 pk (void)bus_intr_establish(fdc->sc_bustag, pri,
591 1.58 pk BUS_INTR_ESTABLISH_FASTTRAP,
592 1.58 pk (int (*) __P((void *)))fdchwintr, NULL);
593 1.2 pk #endif
594 1.58 pk (void)bus_intr_establish(fdc->sc_bustag, PIL_FDSOFT,
595 1.58 pk BUS_INTR_ESTABLISH_SOFTINTR,
596 1.58 pk fdcswintr, fdc);
597 1.1 pk
598 1.14 pk evcnt_attach(&fdc->sc_dev, "intr", &fdc->sc_intrcnt);
599 1.1 pk
600 1.1 pk /* physical limit: four drives per controller. */
601 1.1 pk for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
602 1.1 pk fa.fa_deftype = NULL; /* unknown */
603 1.1 pk fa.fa_deftype = &fd_types[0]; /* XXX */
604 1.58 pk (void)config_found(&fdc->sc_dev, (void *)&fa, fdprint);
605 1.1 pk }
606 1.1 pk }
607 1.1 pk
608 1.1 pk int
609 1.1 pk fdmatch(parent, match, aux)
610 1.1 pk struct device *parent;
611 1.44 pk struct cfdata *match;
612 1.44 pk void *aux;
613 1.1 pk {
614 1.1 pk struct fdc_softc *fdc = (void *)parent;
615 1.70 pk bus_space_tag_t t = fdc->sc_bustag;
616 1.70 pk bus_space_handle_t h = fdc->sc_handle;
617 1.1 pk struct fdc_attach_args *fa = aux;
618 1.1 pk int drive = fa->fa_drive;
619 1.33 pk int n, ok;
620 1.1 pk
621 1.8 pk if (drive > 0)
622 1.50 pk /* XXX - for now, punt on more than one drive */
623 1.42 pk return (0);
624 1.8 pk
625 1.1 pk if (fdc->sc_flags & FDC_82077) {
626 1.1 pk /* select drive and turn on motor */
627 1.70 pk bus_space_write_1(t, h, fdc->sc_reg_dor,
628 1.70 pk drive | FDO_FRST | FDO_MOEN(drive));
629 1.1 pk /* wait for motor to spin up */
630 1.1 pk delay(250000);
631 1.1 pk } else {
632 1.49 pk auxregbisc(AUXIO4C_FDS, 0);
633 1.1 pk }
634 1.1 pk fdc->sc_nstat = 0;
635 1.1 pk out_fdc(fdc, NE7CMD_RECAL);
636 1.1 pk out_fdc(fdc, drive);
637 1.70 pk
638 1.70 pk /* Wait for recalibration to complete */
639 1.33 pk for (n = 0; n < 10000; n++) {
640 1.70 pk u_int8_t v;
641 1.70 pk
642 1.33 pk delay(1000);
643 1.70 pk v = bus_space_read_1(t, h, fdc->sc_reg_msr);
644 1.70 pk if ((v & (NE7_RQM|NE7_DIO|NE7_CB)) == NE7_RQM) {
645 1.2 pk /* wait a bit longer till device *really* is ready */
646 1.2 pk delay(100000);
647 1.2 pk if (out_fdc(fdc, NE7CMD_SENSEI))
648 1.2 pk break;
649 1.7 pk if (fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x80)
650 1.2 pk /*
651 1.2 pk * Got `invalid command'; we interpret it
652 1.2 pk * to mean that the re-calibrate hasn't in
653 1.2 pk * fact finished yet
654 1.2 pk */
655 1.2 pk continue;
656 1.1 pk break;
657 1.1 pk }
658 1.1 pk }
659 1.1 pk n = fdc->sc_nstat;
660 1.1 pk #ifdef FD_DEBUG
661 1.2 pk if (fdc_debug) {
662 1.1 pk int i;
663 1.39 christos printf("fdprobe: %d stati:", n);
664 1.1 pk for (i = 0; i < n; i++)
665 1.52 fair printf(" 0x%x", fdc->sc_status[i]);
666 1.39 christos printf("\n");
667 1.1 pk }
668 1.1 pk #endif
669 1.33 pk ok = (n == 2 && (fdc->sc_status[0] & 0xf8) == 0x20) ? 1 : 0;
670 1.33 pk
671 1.1 pk /* turn off motor */
672 1.1 pk if (fdc->sc_flags & FDC_82077) {
673 1.50 pk /* deselect drive and turn motor off */
674 1.70 pk bus_space_write_1(t, h, fdc->sc_reg_dor, FDO_FRST | FDO_DS);
675 1.1 pk } else {
676 1.49 pk auxregbisc(0, AUXIO4C_FDS);
677 1.1 pk }
678 1.1 pk
679 1.42 pk return (ok);
680 1.1 pk }
681 1.1 pk
682 1.1 pk /*
683 1.1 pk * Controller is working, and drive responded. Attach it.
684 1.1 pk */
685 1.1 pk void
686 1.1 pk fdattach(parent, self, aux)
687 1.1 pk struct device *parent, *self;
688 1.1 pk void *aux;
689 1.1 pk {
690 1.1 pk struct fdc_softc *fdc = (void *)parent;
691 1.1 pk struct fd_softc *fd = (void *)self;
692 1.1 pk struct fdc_attach_args *fa = aux;
693 1.1 pk struct fd_type *type = fa->fa_deftype;
694 1.1 pk int drive = fa->fa_drive;
695 1.1 pk
696 1.1 pk /* XXX Allow `flags' to override device type? */
697 1.1 pk
698 1.1 pk if (type)
699 1.39 christos printf(": %s %d cyl, %d head, %d sec\n", type->name,
700 1.49 pk type->cylinders, type->heads, type->sectrac);
701 1.1 pk else
702 1.39 christos printf(": density unknown\n");
703 1.1 pk
704 1.1 pk fd->sc_cylin = -1;
705 1.1 pk fd->sc_drive = drive;
706 1.1 pk fd->sc_deftype = type;
707 1.1 pk fdc->sc_fd[drive] = fd;
708 1.16 thorpej
709 1.50 pk out_fdc(fdc, NE7CMD_SPECIFY);
710 1.50 pk out_fdc(fdc, type->steprate);
711 1.50 pk out_fdc(fdc, 6 | NE7_SPECIFY_NODMA);
712 1.50 pk
713 1.16 thorpej /*
714 1.16 thorpej * Initialize and attach the disk structure.
715 1.16 thorpej */
716 1.16 thorpej fd->sc_dk.dk_name = fd->sc_dv.dv_xname;
717 1.1 pk fd->sc_dk.dk_driver = &fddkdriver;
718 1.16 thorpej disk_attach(&fd->sc_dk);
719 1.13 pk
720 1.19 thorpej /*
721 1.19 thorpej * Establish a mountroot_hook anyway in case we booted
722 1.19 thorpej * with RB_ASKNAME and get selected as the boot device.
723 1.19 thorpej */
724 1.47 thorpej mountroothook_establish(fd_mountroot_hook, &fd->sc_dv);
725 1.20 thorpej
726 1.20 thorpej /* Make sure the drive motor gets turned off at shutdown time. */
727 1.20 thorpej fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
728 1.19 thorpej
729 1.1 pk /* XXX Need to do some more fiddling with sc_dk. */
730 1.16 thorpej dk_establish(&fd->sc_dk, &fd->sc_dv);
731 1.1 pk }
732 1.1 pk
733 1.24 christos __inline struct fd_type *
734 1.1 pk fd_dev_to_type(fd, dev)
735 1.1 pk struct fd_softc *fd;
736 1.1 pk dev_t dev;
737 1.1 pk {
738 1.1 pk int type = FDTYPE(dev);
739 1.1 pk
740 1.1 pk if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
741 1.42 pk return (NULL);
742 1.42 pk return (type ? &fd_types[type - 1] : fd->sc_deftype);
743 1.1 pk }
744 1.1 pk
745 1.1 pk void
746 1.1 pk fdstrategy(bp)
747 1.1 pk register struct buf *bp; /* IO operation to perform */
748 1.1 pk {
749 1.1 pk struct fd_softc *fd;
750 1.1 pk int unit = FDUNIT(bp->b_dev);
751 1.1 pk int sz;
752 1.1 pk int s;
753 1.1 pk
754 1.1 pk /* Valid unit, controller, and request? */
755 1.26 thorpej if (unit >= fd_cd.cd_ndevs ||
756 1.26 thorpej (fd = fd_cd.cd_devs[unit]) == 0 ||
757 1.1 pk bp->b_blkno < 0 ||
758 1.53 pk (((bp->b_bcount % FD_BSIZE(fd)) != 0 ||
759 1.53 pk (bp->b_blkno * DEV_BSIZE) % FD_BSIZE(fd) != 0) &&
760 1.43 pk (bp->b_flags & B_FORMAT) == 0)) {
761 1.1 pk bp->b_error = EINVAL;
762 1.1 pk goto bad;
763 1.1 pk }
764 1.1 pk
765 1.1 pk /* If it's a null transfer, return immediately. */
766 1.1 pk if (bp->b_bcount == 0)
767 1.1 pk goto done;
768 1.1 pk
769 1.53 pk sz = howmany(bp->b_bcount, DEV_BSIZE);
770 1.1 pk
771 1.53 pk if (bp->b_blkno + sz > (fd->sc_type->size * DEV_BSIZE) / FD_BSIZE(fd)) {
772 1.53 pk sz = (fd->sc_type->size * DEV_BSIZE) / FD_BSIZE(fd)
773 1.53 pk - bp->b_blkno;
774 1.1 pk if (sz == 0) {
775 1.1 pk /* If exactly at end of disk, return EOF. */
776 1.1 pk bp->b_resid = bp->b_bcount;
777 1.1 pk goto done;
778 1.1 pk }
779 1.1 pk if (sz < 0) {
780 1.1 pk /* If past end of disk, return EINVAL. */
781 1.1 pk bp->b_error = EINVAL;
782 1.1 pk goto bad;
783 1.1 pk }
784 1.1 pk /* Otherwise, truncate request. */
785 1.1 pk bp->b_bcount = sz << DEV_BSHIFT;
786 1.1 pk }
787 1.1 pk
788 1.53 pk bp->b_cylin = (bp->b_blkno * DEV_BSIZE) /
789 1.53 pk (FD_BSIZE(fd) * fd->sc_type->seccyl);
790 1.1 pk
791 1.1 pk #ifdef FD_DEBUG
792 1.2 pk if (fdc_debug > 1)
793 1.39 christos printf("fdstrategy: b_blkno %d b_bcount %ld blkno %d cylin %ld\n",
794 1.2 pk bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylin);
795 1.1 pk #endif
796 1.1 pk
797 1.1 pk /* Queue transfer on drive, activate drive and controller if idle. */
798 1.1 pk s = splbio();
799 1.1 pk disksort(&fd->sc_q, bp);
800 1.1 pk untimeout(fd_motor_off, fd); /* a good idea */
801 1.1 pk if (!fd->sc_q.b_active)
802 1.1 pk fdstart(fd);
803 1.1 pk #ifdef DIAGNOSTIC
804 1.1 pk else {
805 1.16 thorpej struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
806 1.1 pk if (fdc->sc_state == DEVIDLE) {
807 1.39 christos printf("fdstrategy: controller inactive\n");
808 1.1 pk fdcstart(fdc);
809 1.1 pk }
810 1.1 pk }
811 1.1 pk #endif
812 1.1 pk splx(s);
813 1.1 pk return;
814 1.1 pk
815 1.1 pk bad:
816 1.1 pk bp->b_flags |= B_ERROR;
817 1.1 pk done:
818 1.1 pk /* Toss transfer; we're done early. */
819 1.1 pk biodone(bp);
820 1.1 pk }
821 1.1 pk
822 1.1 pk void
823 1.1 pk fdstart(fd)
824 1.1 pk struct fd_softc *fd;
825 1.1 pk {
826 1.16 thorpej struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
827 1.1 pk int active = fdc->sc_drives.tqh_first != 0;
828 1.1 pk
829 1.1 pk /* Link into controller queue. */
830 1.1 pk fd->sc_q.b_active = 1;
831 1.1 pk TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
832 1.1 pk
833 1.1 pk /* If controller not already active, start it. */
834 1.1 pk if (!active)
835 1.1 pk fdcstart(fdc);
836 1.1 pk }
837 1.1 pk
838 1.1 pk void
839 1.1 pk fdfinish(fd, bp)
840 1.1 pk struct fd_softc *fd;
841 1.1 pk struct buf *bp;
842 1.1 pk {
843 1.16 thorpej struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
844 1.1 pk
845 1.1 pk /*
846 1.1 pk * Move this drive to the end of the queue to give others a `fair'
847 1.1 pk * chance. We only force a switch if N operations are completed while
848 1.1 pk * another drive is waiting to be serviced, since there is a long motor
849 1.1 pk * startup delay whenever we switch.
850 1.1 pk */
851 1.1 pk if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
852 1.1 pk fd->sc_ops = 0;
853 1.1 pk TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
854 1.1 pk if (bp->b_actf) {
855 1.1 pk TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
856 1.1 pk } else
857 1.1 pk fd->sc_q.b_active = 0;
858 1.1 pk }
859 1.1 pk bp->b_resid = fd->sc_bcount;
860 1.1 pk fd->sc_skip = 0;
861 1.1 pk fd->sc_q.b_actf = bp->b_actf;
862 1.16 thorpej
863 1.1 pk biodone(bp);
864 1.1 pk /* turn off motor 5s from now */
865 1.1 pk timeout(fd_motor_off, fd, 5 * hz);
866 1.1 pk fdc->sc_state = DEVIDLE;
867 1.1 pk }
868 1.1 pk
869 1.1 pk void
870 1.12 pk fdc_reset(fdc)
871 1.12 pk struct fdc_softc *fdc;
872 1.12 pk {
873 1.70 pk bus_space_tag_t t = fdc->sc_bustag;
874 1.70 pk bus_space_handle_t h = fdc->sc_handle;
875 1.70 pk
876 1.12 pk if (fdc->sc_flags & FDC_82077) {
877 1.70 pk bus_space_write_1(t, h, fdc->sc_reg_dor,
878 1.70 pk FDO_FDMAEN | FDO_MOEN(0));
879 1.12 pk }
880 1.12 pk
881 1.70 pk bus_space_write_1(t, h, fdc->sc_reg_drs, DRS_RESET);
882 1.12 pk delay(10);
883 1.70 pk bus_space_write_1(t, h, fdc->sc_reg_drs, 0);
884 1.50 pk
885 1.50 pk if (fdc->sc_flags & FDC_82077) {
886 1.70 pk bus_space_write_1(t, h, fdc->sc_reg_dor,
887 1.70 pk FDO_FRST | FDO_FDMAEN | FDO_DS);
888 1.50 pk }
889 1.12 pk #ifdef FD_DEBUG
890 1.12 pk if (fdc_debug)
891 1.39 christos printf("fdc reset\n");
892 1.12 pk #endif
893 1.12 pk }
894 1.12 pk
895 1.12 pk void
896 1.12 pk fd_set_motor(fdc)
897 1.1 pk struct fdc_softc *fdc;
898 1.1 pk {
899 1.1 pk struct fd_softc *fd;
900 1.1 pk u_char status;
901 1.1 pk int n;
902 1.1 pk
903 1.1 pk if (fdc->sc_flags & FDC_82077) {
904 1.12 pk status = FDO_FRST | FDO_FDMAEN;
905 1.24 christos if ((fd = fdc->sc_drives.tqh_first) != NULL)
906 1.12 pk status |= fd->sc_drive;
907 1.12 pk
908 1.1 pk for (n = 0; n < 4; n++)
909 1.1 pk if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
910 1.1 pk status |= FDO_MOEN(n);
911 1.70 pk bus_space_write_1(fdc->sc_bustag, fdc->sc_handle,
912 1.70 pk fdc->sc_reg_dor, status);
913 1.1 pk } else {
914 1.1 pk int on = 0;
915 1.1 pk
916 1.1 pk for (n = 0; n < 4; n++)
917 1.1 pk if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
918 1.1 pk on = 1;
919 1.1 pk if (on) {
920 1.49 pk auxregbisc(AUXIO4C_FDS, 0);
921 1.1 pk } else {
922 1.49 pk auxregbisc(0, AUXIO4C_FDS);
923 1.1 pk }
924 1.1 pk }
925 1.1 pk }
926 1.1 pk
927 1.1 pk void
928 1.1 pk fd_motor_off(arg)
929 1.1 pk void *arg;
930 1.1 pk {
931 1.1 pk struct fd_softc *fd = arg;
932 1.1 pk int s;
933 1.1 pk
934 1.1 pk s = splbio();
935 1.1 pk fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
936 1.16 thorpej fd_set_motor((struct fdc_softc *)fd->sc_dv.dv_parent);
937 1.1 pk splx(s);
938 1.1 pk }
939 1.1 pk
940 1.1 pk void
941 1.1 pk fd_motor_on(arg)
942 1.1 pk void *arg;
943 1.1 pk {
944 1.1 pk struct fd_softc *fd = arg;
945 1.16 thorpej struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
946 1.1 pk int s;
947 1.1 pk
948 1.1 pk s = splbio();
949 1.1 pk fd->sc_flags &= ~FD_MOTOR_WAIT;
950 1.1 pk if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
951 1.42 pk (void) fdcstate(fdc);
952 1.1 pk splx(s);
953 1.1 pk }
954 1.1 pk
955 1.1 pk int
956 1.1 pk fdcresult(fdc)
957 1.1 pk struct fdc_softc *fdc;
958 1.1 pk {
959 1.70 pk bus_space_tag_t t = fdc->sc_bustag;
960 1.70 pk bus_space_handle_t h = fdc->sc_handle;
961 1.1 pk int j = 100000,
962 1.1 pk n = 0;
963 1.1 pk
964 1.1 pk for (; j; j--) {
965 1.70 pk u_int8_t v = bus_space_read_1(t, h, fdc->sc_reg_msr);
966 1.70 pk v &= (NE7_DIO | NE7_RQM | NE7_CB);
967 1.70 pk if (v == NE7_RQM)
968 1.1 pk return (fdc->sc_nstat = n);
969 1.70 pk if (v == (NE7_DIO | NE7_RQM | NE7_CB)) {
970 1.1 pk if (n >= sizeof(fdc->sc_status)) {
971 1.1 pk log(LOG_ERR, "fdcresult: overrun\n");
972 1.42 pk return (-1);
973 1.1 pk }
974 1.70 pk fdc->sc_status[n++] =
975 1.70 pk bus_space_read_1(t, h, fdc->sc_reg_fifo);
976 1.41 pk } else
977 1.41 pk delay(10);
978 1.1 pk }
979 1.1 pk log(LOG_ERR, "fdcresult: timeout\n");
980 1.1 pk return (fdc->sc_nstat = -1);
981 1.1 pk }
982 1.1 pk
983 1.1 pk int
984 1.1 pk out_fdc(fdc, x)
985 1.1 pk struct fdc_softc *fdc;
986 1.70 pk u_int8_t x;
987 1.1 pk {
988 1.70 pk bus_space_tag_t t = fdc->sc_bustag;
989 1.70 pk bus_space_handle_t h = fdc->sc_handle;
990 1.70 pk int i;
991 1.70 pk
992 1.70 pk for (i = 100000; i-- > 0;) {
993 1.70 pk u_int8_t v = bus_space_read_1(t, h, fdc->sc_reg_msr);
994 1.70 pk if ((v & (NE7_DIO|NE7_RQM)) == NE7_RQM)
995 1.70 pk break;
996 1.41 pk delay(1);
997 1.70 pk }
998 1.1 pk if (i <= 0)
999 1.42 pk return (-1);
1000 1.1 pk
1001 1.70 pk bus_space_write_1(t, h, fdc->sc_reg_fifo, x);
1002 1.42 pk return (0);
1003 1.1 pk }
1004 1.1 pk
1005 1.1 pk int
1006 1.24 christos fdopen(dev, flags, fmt, p)
1007 1.1 pk dev_t dev;
1008 1.19 thorpej int flags, fmt;
1009 1.19 thorpej struct proc *p;
1010 1.1 pk {
1011 1.19 thorpej int unit, pmask;
1012 1.1 pk struct fd_softc *fd;
1013 1.1 pk struct fd_type *type;
1014 1.1 pk
1015 1.1 pk unit = FDUNIT(dev);
1016 1.26 thorpej if (unit >= fd_cd.cd_ndevs)
1017 1.42 pk return (ENXIO);
1018 1.26 thorpej fd = fd_cd.cd_devs[unit];
1019 1.1 pk if (fd == 0)
1020 1.42 pk return (ENXIO);
1021 1.1 pk type = fd_dev_to_type(fd, dev);
1022 1.1 pk if (type == NULL)
1023 1.42 pk return (ENXIO);
1024 1.1 pk
1025 1.1 pk if ((fd->sc_flags & FD_OPEN) != 0 &&
1026 1.1 pk fd->sc_type != type)
1027 1.42 pk return (EBUSY);
1028 1.1 pk
1029 1.1 pk fd->sc_type = type;
1030 1.1 pk fd->sc_cylin = -1;
1031 1.1 pk fd->sc_flags |= FD_OPEN;
1032 1.1 pk
1033 1.19 thorpej /*
1034 1.19 thorpej * Only update the disklabel if we're not open anywhere else.
1035 1.19 thorpej */
1036 1.19 thorpej if (fd->sc_dk.dk_openmask == 0)
1037 1.19 thorpej fdgetdisklabel(dev);
1038 1.19 thorpej
1039 1.19 thorpej pmask = (1 << DISKPART(dev));
1040 1.19 thorpej
1041 1.19 thorpej switch (fmt) {
1042 1.19 thorpej case S_IFCHR:
1043 1.19 thorpej fd->sc_dk.dk_copenmask |= pmask;
1044 1.19 thorpej break;
1045 1.19 thorpej
1046 1.19 thorpej case S_IFBLK:
1047 1.19 thorpej fd->sc_dk.dk_bopenmask |= pmask;
1048 1.19 thorpej break;
1049 1.19 thorpej }
1050 1.19 thorpej fd->sc_dk.dk_openmask =
1051 1.19 thorpej fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask;
1052 1.19 thorpej
1053 1.42 pk return (0);
1054 1.1 pk }
1055 1.1 pk
1056 1.1 pk int
1057 1.19 thorpej fdclose(dev, flags, fmt, p)
1058 1.1 pk dev_t dev;
1059 1.19 thorpej int flags, fmt;
1060 1.19 thorpej struct proc *p;
1061 1.1 pk {
1062 1.26 thorpej struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1063 1.19 thorpej int pmask = (1 << DISKPART(dev));
1064 1.1 pk
1065 1.1 pk fd->sc_flags &= ~FD_OPEN;
1066 1.42 pk fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
1067 1.19 thorpej
1068 1.19 thorpej switch (fmt) {
1069 1.19 thorpej case S_IFCHR:
1070 1.19 thorpej fd->sc_dk.dk_copenmask &= ~pmask;
1071 1.19 thorpej break;
1072 1.19 thorpej
1073 1.19 thorpej case S_IFBLK:
1074 1.19 thorpej fd->sc_dk.dk_bopenmask &= ~pmask;
1075 1.19 thorpej break;
1076 1.19 thorpej }
1077 1.29 pk fd->sc_dk.dk_openmask =
1078 1.19 thorpej fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask;
1079 1.19 thorpej
1080 1.42 pk return (0);
1081 1.9 pk }
1082 1.9 pk
1083 1.9 pk int
1084 1.24 christos fdread(dev, uio, flag)
1085 1.9 pk dev_t dev;
1086 1.9 pk struct uio *uio;
1087 1.24 christos int flag;
1088 1.9 pk {
1089 1.9 pk
1090 1.9 pk return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
1091 1.9 pk }
1092 1.9 pk
1093 1.9 pk int
1094 1.24 christos fdwrite(dev, uio, flag)
1095 1.9 pk dev_t dev;
1096 1.9 pk struct uio *uio;
1097 1.24 christos int flag;
1098 1.9 pk {
1099 1.9 pk
1100 1.9 pk return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
1101 1.1 pk }
1102 1.1 pk
1103 1.1 pk void
1104 1.1 pk fdcstart(fdc)
1105 1.1 pk struct fdc_softc *fdc;
1106 1.1 pk {
1107 1.1 pk
1108 1.1 pk #ifdef DIAGNOSTIC
1109 1.1 pk /* only got here if controller's drive queue was inactive; should
1110 1.1 pk be in idle state */
1111 1.1 pk if (fdc->sc_state != DEVIDLE) {
1112 1.39 christos printf("fdcstart: not idle\n");
1113 1.1 pk return;
1114 1.1 pk }
1115 1.1 pk #endif
1116 1.42 pk (void) fdcstate(fdc);
1117 1.1 pk }
1118 1.1 pk
1119 1.1 pk void
1120 1.1 pk fdcstatus(dv, n, s)
1121 1.1 pk struct device *dv;
1122 1.1 pk int n;
1123 1.1 pk char *s;
1124 1.1 pk {
1125 1.1 pk struct fdc_softc *fdc = (void *)dv->dv_parent;
1126 1.40 thorpej char bits[64];
1127 1.1 pk #if 0
1128 1.1 pk /*
1129 1.1 pk * A 82072 seems to return <invalid command> on
1130 1.1 pk * gratuitous Sense Interrupt commands.
1131 1.1 pk */
1132 1.1 pk if (n == 0 && (fdc->sc_flags & FDC_82077)) {
1133 1.1 pk out_fdc(fdc, NE7CMD_SENSEI);
1134 1.1 pk (void) fdcresult(fdc);
1135 1.1 pk n = 2;
1136 1.1 pk }
1137 1.1 pk #endif
1138 1.1 pk
1139 1.1 pk /* Just print last status */
1140 1.1 pk n = fdc->sc_nstat;
1141 1.1 pk
1142 1.39 christos printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
1143 1.1 pk
1144 1.1 pk switch (n) {
1145 1.1 pk case 0:
1146 1.39 christos printf("\n");
1147 1.1 pk break;
1148 1.1 pk case 2:
1149 1.40 thorpej printf(" (st0 %s cyl %d)\n",
1150 1.40 thorpej bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
1151 1.40 thorpej bits, sizeof(bits)), fdc->sc_status[1]);
1152 1.1 pk break;
1153 1.1 pk case 7:
1154 1.40 thorpej printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1155 1.40 thorpej NE7_ST0BITS, bits, sizeof(bits)));
1156 1.40 thorpej printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1157 1.40 thorpej NE7_ST1BITS, bits, sizeof(bits)));
1158 1.40 thorpej printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1159 1.40 thorpej NE7_ST2BITS, bits, sizeof(bits)));
1160 1.40 thorpej printf(" cyl %d head %d sec %d)\n",
1161 1.1 pk fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1162 1.1 pk break;
1163 1.1 pk #ifdef DIAGNOSTIC
1164 1.1 pk default:
1165 1.39 christos printf(" fdcstatus: weird size: %d\n", n);
1166 1.1 pk break;
1167 1.1 pk #endif
1168 1.1 pk }
1169 1.1 pk }
1170 1.1 pk
1171 1.1 pk void
1172 1.1 pk fdctimeout(arg)
1173 1.1 pk void *arg;
1174 1.1 pk {
1175 1.1 pk struct fdc_softc *fdc = arg;
1176 1.1 pk struct fd_softc *fd = fdc->sc_drives.tqh_first;
1177 1.1 pk int s;
1178 1.1 pk
1179 1.1 pk s = splbio();
1180 1.16 thorpej fdcstatus(&fd->sc_dv, 0, "timeout");
1181 1.1 pk
1182 1.1 pk if (fd->sc_q.b_actf)
1183 1.1 pk fdc->sc_state++;
1184 1.1 pk else
1185 1.1 pk fdc->sc_state = DEVIDLE;
1186 1.1 pk
1187 1.42 pk (void) fdcstate(fdc);
1188 1.1 pk splx(s);
1189 1.1 pk }
1190 1.1 pk
1191 1.2 pk void
1192 1.2 pk fdcpseudointr(arg)
1193 1.2 pk void *arg;
1194 1.2 pk {
1195 1.2 pk struct fdc_softc *fdc = arg;
1196 1.2 pk int s;
1197 1.2 pk
1198 1.2 pk /* Just ensure it has the right spl. */
1199 1.2 pk s = splbio();
1200 1.42 pk (void) fdcstate(fdc);
1201 1.2 pk splx(s);
1202 1.2 pk }
1203 1.2 pk
1204 1.2 pk
1205 1.2 pk #ifdef FDC_C_HANDLER
1206 1.1 pk /*
1207 1.1 pk * hardware interrupt entry point: must be converted to `fast'
1208 1.1 pk * (in-window) handler.
1209 1.1 pk */
1210 1.1 pk int
1211 1.58 pk fdchwintr(arg)
1212 1.58 pk void *arg;
1213 1.1 pk {
1214 1.58 pk struct fdc_softc *fdc = arg;
1215 1.70 pk bus_space_tag_t t = fdc->sc_bustag;
1216 1.70 pk bus_space_handle_t h = fdc->sc_handle;
1217 1.1 pk
1218 1.2 pk switch (fdc->sc_istate) {
1219 1.42 pk case ISTATE_IDLE:
1220 1.42 pk return (0);
1221 1.2 pk case ISTATE_SENSEI:
1222 1.1 pk out_fdc(fdc, NE7CMD_SENSEI);
1223 1.1 pk fdcresult(fdc);
1224 1.2 pk fdc->sc_istate = ISTATE_IDLE;
1225 1.42 pk FD_SET_SWINTR;
1226 1.42 pk return (1);
1227 1.2 pk case ISTATE_SPURIOUS:
1228 1.1 pk fdcresult(fdc);
1229 1.2 pk fdc->sc_istate = ISTATE_SPURIOUS;
1230 1.39 christos printf("fdc: stray hard interrupt... ");
1231 1.42 pk FD_SET_SWINTR;
1232 1.42 pk return (1);
1233 1.2 pk case ISTATE_DMA:
1234 1.2 pk break;
1235 1.2 pk default:
1236 1.39 christos printf("fdc: goofed ...\n");
1237 1.42 pk return (1);
1238 1.1 pk }
1239 1.1 pk
1240 1.1 pk for (;;) {
1241 1.70 pk u_int8_t msr;
1242 1.1 pk
1243 1.70 pk msr = bus_space_read_1(t, h, fdc->sc_reg_msr);
1244 1.1 pk
1245 1.1 pk if ((msr & NE7_RQM) == 0)
1246 1.1 pk break;
1247 1.1 pk
1248 1.1 pk if ((msr & NE7_NDM) == 0) {
1249 1.1 pk fdcresult(fdc);
1250 1.2 pk fdc->sc_istate = ISTATE_IDLE;
1251 1.1 pk ienab_bis(IE_FDSOFT);
1252 1.39 christos printf("fdc: overrun: tc = %d\n", fdc->sc_tc);
1253 1.1 pk break;
1254 1.1 pk }
1255 1.1 pk
1256 1.1 pk if (msr & NE7_DIO) {
1257 1.70 pk *fdc->sc_data++ =
1258 1.70 pk bus_space_read_1(t, h, fdc->sc_reg_fifo);
1259 1.1 pk } else {
1260 1.70 pk bus_space_write_1(t, h, fdc->sc_reg_fifo,
1261 1.70 pk *fdc->sc_data);
1262 1.70 pk fdc->sc_data++;
1263 1.1 pk }
1264 1.1 pk if (--fdc->sc_tc == 0) {
1265 1.50 pk fdc->sc_istate = ISTATE_DONE;
1266 1.49 pk FTC_FLIP;
1267 1.1 pk fdcresult(fdc);
1268 1.42 pk FD_SET_SWINTR;
1269 1.1 pk break;
1270 1.1 pk }
1271 1.1 pk }
1272 1.42 pk return (1);
1273 1.1 pk }
1274 1.2 pk #endif
1275 1.1 pk
1276 1.1 pk int
1277 1.58 pk fdcswintr(arg)
1278 1.58 pk void *arg;
1279 1.1 pk {
1280 1.58 pk struct fdc_softc *fdc = arg;
1281 1.42 pk int s;
1282 1.42 pk
1283 1.42 pk if (fdc->sc_istate != ISTATE_DONE)
1284 1.42 pk return (0);
1285 1.42 pk
1286 1.42 pk fdc->sc_istate = ISTATE_IDLE;
1287 1.42 pk s = splbio();
1288 1.42 pk fdcstate(fdc);
1289 1.42 pk splx(s);
1290 1.42 pk return (1);
1291 1.42 pk }
1292 1.42 pk
1293 1.42 pk int
1294 1.42 pk fdcstate(fdc)
1295 1.42 pk struct fdc_softc *fdc;
1296 1.42 pk {
1297 1.1 pk #define st0 fdc->sc_status[0]
1298 1.1 pk #define st1 fdc->sc_status[1]
1299 1.1 pk #define cyl fdc->sc_status[1]
1300 1.2 pk #define OUT_FDC(fdc, c, s) \
1301 1.2 pk do { if (out_fdc(fdc, (c))) { (fdc)->sc_state = (s); goto loop; } } while(0)
1302 1.2 pk
1303 1.1 pk struct fd_softc *fd;
1304 1.1 pk struct buf *bp;
1305 1.24 christos int read, head, sec, nblks;
1306 1.1 pk struct fd_type *type;
1307 1.43 pk struct ne7_fd_formb *finfo = NULL;
1308 1.1 pk
1309 1.12 pk
1310 1.2 pk if (fdc->sc_istate != ISTATE_IDLE) {
1311 1.2 pk /* Trouble... */
1312 1.39 christos printf("fdc: spurious interrupt: state %d, istate=%d\n",
1313 1.12 pk fdc->sc_state, fdc->sc_istate);
1314 1.2 pk fdc->sc_istate = ISTATE_IDLE;
1315 1.12 pk if (fdc->sc_state == RESETCOMPLETE ||
1316 1.12 pk fdc->sc_state == RESETTIMEDOUT) {
1317 1.12 pk panic("fdcintr: spurious interrupt can't be cleared");
1318 1.12 pk }
1319 1.2 pk goto doreset;
1320 1.2 pk }
1321 1.2 pk
1322 1.12 pk loop:
1323 1.1 pk /* Is there a drive for the controller to do a transfer with? */
1324 1.1 pk fd = fdc->sc_drives.tqh_first;
1325 1.1 pk if (fd == NULL) {
1326 1.1 pk fdc->sc_state = DEVIDLE;
1327 1.42 pk return (0);
1328 1.1 pk }
1329 1.1 pk
1330 1.1 pk /* Is there a transfer to this drive? If not, deactivate drive. */
1331 1.1 pk bp = fd->sc_q.b_actf;
1332 1.1 pk if (bp == NULL) {
1333 1.1 pk fd->sc_ops = 0;
1334 1.1 pk TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1335 1.1 pk fd->sc_q.b_active = 0;
1336 1.1 pk goto loop;
1337 1.1 pk }
1338 1.1 pk
1339 1.43 pk if (bp->b_flags & B_FORMAT)
1340 1.43 pk finfo = (struct ne7_fd_formb *)bp->b_data;
1341 1.43 pk
1342 1.1 pk switch (fdc->sc_state) {
1343 1.1 pk case DEVIDLE:
1344 1.1 pk fdc->sc_errors = 0;
1345 1.1 pk fd->sc_skip = 0;
1346 1.1 pk fd->sc_bcount = bp->b_bcount;
1347 1.53 pk fd->sc_blkno = (bp->b_blkno * DEV_BSIZE) / FD_BSIZE(fd);
1348 1.1 pk untimeout(fd_motor_off, fd);
1349 1.1 pk if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1350 1.1 pk fdc->sc_state = MOTORWAIT;
1351 1.42 pk return (1);
1352 1.1 pk }
1353 1.1 pk if ((fd->sc_flags & FD_MOTOR) == 0) {
1354 1.1 pk /* Turn on the motor, being careful about pairing. */
1355 1.1 pk struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
1356 1.1 pk if (ofd && ofd->sc_flags & FD_MOTOR) {
1357 1.1 pk untimeout(fd_motor_off, ofd);
1358 1.1 pk ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1359 1.1 pk }
1360 1.1 pk fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1361 1.12 pk fd_set_motor(fdc);
1362 1.1 pk fdc->sc_state = MOTORWAIT;
1363 1.2 pk if (fdc->sc_flags & FDC_82077) { /* XXX */
1364 1.2 pk /* Allow .25s for motor to stabilize. */
1365 1.2 pk timeout(fd_motor_on, fd, hz / 4);
1366 1.2 pk } else {
1367 1.2 pk fd->sc_flags &= ~FD_MOTOR_WAIT;
1368 1.2 pk goto loop;
1369 1.2 pk }
1370 1.42 pk return (1);
1371 1.1 pk }
1372 1.1 pk /* Make sure the right drive is selected. */
1373 1.12 pk fd_set_motor(fdc);
1374 1.1 pk
1375 1.49 pk /*FALLTHROUGH*/
1376 1.1 pk case DOSEEK:
1377 1.1 pk doseek:
1378 1.43 pk if ((fdc->sc_flags & FDC_EIS) &&
1379 1.43 pk (bp->b_flags & B_FORMAT) == 0) {
1380 1.2 pk fd->sc_cylin = bp->b_cylin;
1381 1.2 pk /* We use implied seek */
1382 1.2 pk goto doio;
1383 1.2 pk }
1384 1.2 pk
1385 1.1 pk if (fd->sc_cylin == bp->b_cylin)
1386 1.1 pk goto doio;
1387 1.1 pk
1388 1.2 pk /* specify command */
1389 1.2 pk OUT_FDC(fdc, NE7CMD_SPECIFY, SEEKTIMEDOUT);
1390 1.2 pk OUT_FDC(fdc, fd->sc_type->steprate, SEEKTIMEDOUT);
1391 1.50 pk /* XXX head load time == 6ms */
1392 1.50 pk OUT_FDC(fdc, 6 | NE7_SPECIFY_NODMA, SEEKTIMEDOUT);
1393 1.2 pk
1394 1.2 pk fdc->sc_istate = ISTATE_SENSEI;
1395 1.2 pk /* seek function */
1396 1.2 pk OUT_FDC(fdc, NE7CMD_SEEK, SEEKTIMEDOUT);
1397 1.2 pk OUT_FDC(fdc, fd->sc_drive, SEEKTIMEDOUT); /* drive number */
1398 1.2 pk OUT_FDC(fdc, bp->b_cylin * fd->sc_type->step, SEEKTIMEDOUT);
1399 1.1 pk
1400 1.1 pk fd->sc_cylin = -1;
1401 1.1 pk fdc->sc_state = SEEKWAIT;
1402 1.1 pk fdc->sc_nstat = 0;
1403 1.18 thorpej
1404 1.18 thorpej fd->sc_dk.dk_seek++;
1405 1.18 thorpej disk_busy(&fd->sc_dk);
1406 1.18 thorpej
1407 1.1 pk timeout(fdctimeout, fdc, 4 * hz);
1408 1.42 pk return (1);
1409 1.1 pk
1410 1.1 pk case DOIO:
1411 1.1 pk doio:
1412 1.50 pk if (finfo != NULL)
1413 1.43 pk fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1414 1.43 pk (char *)finfo;
1415 1.1 pk type = fd->sc_type;
1416 1.1 pk sec = fd->sc_blkno % type->seccyl;
1417 1.1 pk nblks = type->seccyl - sec;
1418 1.53 pk nblks = min(nblks, fd->sc_bcount / FD_BSIZE(fd));
1419 1.53 pk nblks = min(nblks, FDC_MAXIOSIZE / FD_BSIZE(fd));
1420 1.1 pk fd->sc_nblks = nblks;
1421 1.53 pk fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FD_BSIZE(fd);
1422 1.1 pk head = sec / type->sectrac;
1423 1.1 pk sec -= head * type->sectrac;
1424 1.1 pk #ifdef DIAGNOSTIC
1425 1.1 pk {int block;
1426 1.1 pk block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
1427 1.1 pk if (block != fd->sc_blkno) {
1428 1.39 christos printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
1429 1.1 pk #ifdef DDB
1430 1.1 pk Debugger();
1431 1.1 pk #endif
1432 1.1 pk }}
1433 1.1 pk #endif
1434 1.1 pk read = bp->b_flags & B_READ;
1435 1.1 pk
1436 1.1 pk /* Setup for pseudo DMA */
1437 1.2 pk fdc->sc_data = bp->b_data + fd->sc_skip;
1438 1.1 pk fdc->sc_tc = fd->sc_nbytes;
1439 1.1 pk
1440 1.70 pk bus_space_write_1(fdc->sc_bustag, fdc->sc_handle,
1441 1.70 pk fdc->sc_reg_drs, type->rate);
1442 1.1 pk #ifdef FD_DEBUG
1443 1.2 pk if (fdc_debug > 1)
1444 1.39 christos printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1445 1.2 pk read ? "read" : "write", fd->sc_drive,
1446 1.2 pk fd->sc_cylin, head, sec, nblks);
1447 1.1 pk #endif
1448 1.2 pk fdc->sc_state = IOCOMPLETE;
1449 1.2 pk fdc->sc_istate = ISTATE_DMA;
1450 1.1 pk fdc->sc_nstat = 0;
1451 1.50 pk if (finfo != NULL) {
1452 1.43 pk /* formatting */
1453 1.43 pk OUT_FDC(fdc, NE7CMD_FORMAT, IOTIMEDOUT);
1454 1.43 pk OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT);
1455 1.43 pk OUT_FDC(fdc, finfo->fd_formb_secshift, IOTIMEDOUT);
1456 1.43 pk OUT_FDC(fdc, finfo->fd_formb_nsecs, IOTIMEDOUT);
1457 1.43 pk OUT_FDC(fdc, finfo->fd_formb_gaplen, IOTIMEDOUT);
1458 1.43 pk OUT_FDC(fdc, finfo->fd_formb_fillbyte, IOTIMEDOUT);
1459 1.43 pk } else {
1460 1.43 pk if (read)
1461 1.43 pk OUT_FDC(fdc, NE7CMD_READ, IOTIMEDOUT);
1462 1.43 pk else
1463 1.43 pk OUT_FDC(fdc, NE7CMD_WRITE, IOTIMEDOUT);
1464 1.43 pk OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT);
1465 1.43 pk OUT_FDC(fdc, fd->sc_cylin, IOTIMEDOUT); /*track*/
1466 1.43 pk OUT_FDC(fdc, head, IOTIMEDOUT);
1467 1.43 pk OUT_FDC(fdc, sec + 1, IOTIMEDOUT); /*sector+1*/
1468 1.43 pk OUT_FDC(fdc, type->secsize, IOTIMEDOUT);/*sector size*/
1469 1.43 pk OUT_FDC(fdc, type->sectrac, IOTIMEDOUT);/*secs/track*/
1470 1.43 pk OUT_FDC(fdc, type->gap1, IOTIMEDOUT); /*gap1 size*/
1471 1.43 pk OUT_FDC(fdc, type->datalen, IOTIMEDOUT);/*data length*/
1472 1.43 pk }
1473 1.18 thorpej
1474 1.18 thorpej disk_busy(&fd->sc_dk);
1475 1.18 thorpej
1476 1.1 pk /* allow 2 seconds for operation */
1477 1.1 pk timeout(fdctimeout, fdc, 2 * hz);
1478 1.42 pk return (1); /* will return later */
1479 1.1 pk
1480 1.1 pk case SEEKWAIT:
1481 1.1 pk untimeout(fdctimeout, fdc);
1482 1.1 pk fdc->sc_state = SEEKCOMPLETE;
1483 1.2 pk if (fdc->sc_flags & FDC_NEEDHEADSETTLE) {
1484 1.2 pk /* allow 1/50 second for heads to settle */
1485 1.2 pk timeout(fdcpseudointr, fdc, hz / 50);
1486 1.42 pk return (1); /* will return later */
1487 1.2 pk }
1488 1.49 pk /*FALLTHROUGH*/
1489 1.1 pk case SEEKCOMPLETE:
1490 1.18 thorpej disk_unbusy(&fd->sc_dk, 0); /* no data on seek */
1491 1.18 thorpej
1492 1.1 pk /* Make sure seek really happened. */
1493 1.1 pk if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 ||
1494 1.1 pk cyl != bp->b_cylin * fd->sc_type->step) {
1495 1.1 pk #ifdef FD_DEBUG
1496 1.2 pk if (fdc_debug)
1497 1.16 thorpej fdcstatus(&fd->sc_dv, 2, "seek failed");
1498 1.1 pk #endif
1499 1.1 pk fdcretry(fdc);
1500 1.1 pk goto loop;
1501 1.1 pk }
1502 1.1 pk fd->sc_cylin = bp->b_cylin;
1503 1.1 pk goto doio;
1504 1.1 pk
1505 1.1 pk case IOTIMEDOUT:
1506 1.49 pk FTC_FLIP;
1507 1.1 pk (void)fdcresult(fdc);
1508 1.49 pk /*FALLTHROUGH*/
1509 1.1 pk case SEEKTIMEDOUT:
1510 1.1 pk case RECALTIMEDOUT:
1511 1.1 pk case RESETTIMEDOUT:
1512 1.1 pk fdcretry(fdc);
1513 1.1 pk goto loop;
1514 1.1 pk
1515 1.1 pk case IOCOMPLETE: /* IO DONE, post-analyze */
1516 1.1 pk untimeout(fdctimeout, fdc);
1517 1.18 thorpej
1518 1.18 thorpej disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid));
1519 1.18 thorpej
1520 1.50 pk if (fdc->sc_nstat != 7 || st1 != 0 ||
1521 1.50 pk ((st0 & 0xf8) != 0 &&
1522 1.50 pk ((st0 & 0xf8) != 0x20 || (fdc->sc_cfg & CFG_EIS) == 0))) {
1523 1.1 pk #ifdef FD_DEBUG
1524 1.2 pk if (fdc_debug) {
1525 1.16 thorpej fdcstatus(&fd->sc_dv, 7,
1526 1.2 pk bp->b_flags & B_READ
1527 1.2 pk ? "read failed" : "write failed");
1528 1.50 pk printf("blkno %d nblks %d nstat %d tc %d\n",
1529 1.50 pk fd->sc_blkno, fd->sc_nblks,
1530 1.50 pk fdc->sc_nstat, fdc->sc_tc);
1531 1.2 pk }
1532 1.1 pk #endif
1533 1.6 pk if (fdc->sc_nstat == 7 &&
1534 1.6 pk (st1 & ST1_OVERRUN) == ST1_OVERRUN) {
1535 1.6 pk
1536 1.6 pk /*
1537 1.6 pk * Silently retry overruns if no other
1538 1.6 pk * error bit is set. Adjust threshold.
1539 1.6 pk */
1540 1.2 pk int thr = fdc->sc_cfg & CFG_THRHLD_MASK;
1541 1.6 pk if (thr < 15) {
1542 1.6 pk thr++;
1543 1.6 pk fdc->sc_cfg &= ~CFG_THRHLD_MASK;
1544 1.6 pk fdc->sc_cfg |= (thr & CFG_THRHLD_MASK);
1545 1.2 pk #ifdef FD_DEBUG
1546 1.6 pk if (fdc_debug)
1547 1.39 christos printf("fdc: %d -> threshold\n", thr);
1548 1.2 pk #endif
1549 1.6 pk fdconf(fdc);
1550 1.6 pk fdc->sc_overruns = 0;
1551 1.6 pk }
1552 1.34 pk if (++fdc->sc_overruns < 3) {
1553 1.34 pk fdc->sc_state = DOIO;
1554 1.6 pk goto loop;
1555 1.34 pk }
1556 1.2 pk }
1557 1.1 pk fdcretry(fdc);
1558 1.1 pk goto loop;
1559 1.1 pk }
1560 1.1 pk if (fdc->sc_errors) {
1561 1.1 pk diskerr(bp, "fd", "soft error", LOG_PRINTF,
1562 1.53 pk fd->sc_skip / FD_BSIZE(fd),
1563 1.53 pk (struct disklabel *)NULL);
1564 1.39 christos printf("\n");
1565 1.1 pk fdc->sc_errors = 0;
1566 1.6 pk } else {
1567 1.12 pk if (--fdc->sc_overruns < -20) {
1568 1.6 pk int thr = fdc->sc_cfg & CFG_THRHLD_MASK;
1569 1.6 pk if (thr > 0) {
1570 1.6 pk thr--;
1571 1.6 pk fdc->sc_cfg &= ~CFG_THRHLD_MASK;
1572 1.6 pk fdc->sc_cfg |= (thr & CFG_THRHLD_MASK);
1573 1.6 pk #ifdef FD_DEBUG
1574 1.6 pk if (fdc_debug)
1575 1.39 christos printf("fdc: %d -> threshold\n", thr);
1576 1.6 pk #endif
1577 1.6 pk fdconf(fdc);
1578 1.6 pk }
1579 1.6 pk fdc->sc_overruns = 0;
1580 1.6 pk }
1581 1.1 pk }
1582 1.1 pk fd->sc_blkno += fd->sc_nblks;
1583 1.1 pk fd->sc_skip += fd->sc_nbytes;
1584 1.1 pk fd->sc_bcount -= fd->sc_nbytes;
1585 1.50 pk if (finfo == NULL && fd->sc_bcount > 0) {
1586 1.1 pk bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl;
1587 1.1 pk goto doseek;
1588 1.1 pk }
1589 1.1 pk fdfinish(fd, bp);
1590 1.1 pk goto loop;
1591 1.1 pk
1592 1.1 pk case DORESET:
1593 1.2 pk doreset:
1594 1.1 pk /* try a reset, keep motor on */
1595 1.12 pk fd_set_motor(fdc);
1596 1.1 pk delay(100);
1597 1.12 pk fdc_reset(fdc);
1598 1.12 pk fdc->sc_nstat = 0;
1599 1.12 pk fdc->sc_istate = ISTATE_SENSEI;
1600 1.1 pk fdc->sc_state = RESETCOMPLETE;
1601 1.1 pk timeout(fdctimeout, fdc, hz / 2);
1602 1.42 pk return (1); /* will return later */
1603 1.1 pk
1604 1.1 pk case RESETCOMPLETE:
1605 1.1 pk untimeout(fdctimeout, fdc);
1606 1.12 pk fdconf(fdc);
1607 1.1 pk
1608 1.1 pk /* fall through */
1609 1.1 pk case DORECAL:
1610 1.1 pk fdc->sc_state = RECALWAIT;
1611 1.2 pk fdc->sc_istate = ISTATE_SENSEI;
1612 1.1 pk fdc->sc_nstat = 0;
1613 1.2 pk /* recalibrate function */
1614 1.2 pk OUT_FDC(fdc, NE7CMD_RECAL, RECALTIMEDOUT);
1615 1.2 pk OUT_FDC(fdc, fd->sc_drive, RECALTIMEDOUT);
1616 1.1 pk timeout(fdctimeout, fdc, 5 * hz);
1617 1.42 pk return (1); /* will return later */
1618 1.1 pk
1619 1.1 pk case RECALWAIT:
1620 1.1 pk untimeout(fdctimeout, fdc);
1621 1.1 pk fdc->sc_state = RECALCOMPLETE;
1622 1.2 pk if (fdc->sc_flags & FDC_NEEDHEADSETTLE) {
1623 1.2 pk /* allow 1/30 second for heads to settle */
1624 1.2 pk timeout(fdcpseudointr, fdc, hz / 30);
1625 1.42 pk return (1); /* will return later */
1626 1.2 pk }
1627 1.1 pk
1628 1.1 pk case RECALCOMPLETE:
1629 1.1 pk if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1630 1.1 pk #ifdef FD_DEBUG
1631 1.2 pk if (fdc_debug)
1632 1.16 thorpej fdcstatus(&fd->sc_dv, 2, "recalibrate failed");
1633 1.1 pk #endif
1634 1.1 pk fdcretry(fdc);
1635 1.1 pk goto loop;
1636 1.1 pk }
1637 1.1 pk fd->sc_cylin = 0;
1638 1.1 pk goto doseek;
1639 1.1 pk
1640 1.1 pk case MOTORWAIT:
1641 1.1 pk if (fd->sc_flags & FD_MOTOR_WAIT)
1642 1.42 pk return (1); /* time's not up yet */
1643 1.1 pk goto doseek;
1644 1.1 pk
1645 1.1 pk default:
1646 1.16 thorpej fdcstatus(&fd->sc_dv, 0, "stray interrupt");
1647 1.42 pk return (1);
1648 1.1 pk }
1649 1.1 pk #ifdef DIAGNOSTIC
1650 1.1 pk panic("fdcintr: impossible");
1651 1.1 pk #endif
1652 1.1 pk #undef st0
1653 1.1 pk #undef st1
1654 1.1 pk #undef cyl
1655 1.1 pk }
1656 1.1 pk
1657 1.1 pk void
1658 1.1 pk fdcretry(fdc)
1659 1.1 pk struct fdc_softc *fdc;
1660 1.1 pk {
1661 1.40 thorpej char bits[64];
1662 1.1 pk struct fd_softc *fd;
1663 1.1 pk struct buf *bp;
1664 1.1 pk
1665 1.1 pk fd = fdc->sc_drives.tqh_first;
1666 1.1 pk bp = fd->sc_q.b_actf;
1667 1.6 pk
1668 1.6 pk fdc->sc_overruns = 0;
1669 1.42 pk if (fd->sc_opts & FDOPT_NORETRY)
1670 1.42 pk goto fail;
1671 1.1 pk
1672 1.1 pk switch (fdc->sc_errors) {
1673 1.1 pk case 0:
1674 1.1 pk /* try again */
1675 1.2 pk fdc->sc_state =
1676 1.22 thorpej (fdc->sc_flags & FDC_EIS) ? DOIO : DOSEEK;
1677 1.1 pk break;
1678 1.1 pk
1679 1.1 pk case 1: case 2: case 3:
1680 1.1 pk /* didn't work; try recalibrating */
1681 1.1 pk fdc->sc_state = DORECAL;
1682 1.1 pk break;
1683 1.1 pk
1684 1.1 pk case 4:
1685 1.1 pk /* still no go; reset the bastard */
1686 1.1 pk fdc->sc_state = DORESET;
1687 1.1 pk break;
1688 1.1 pk
1689 1.1 pk default:
1690 1.42 pk fail:
1691 1.42 pk if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1692 1.42 pk diskerr(bp, "fd", "hard error", LOG_PRINTF,
1693 1.53 pk fd->sc_skip / FD_BSIZE(fd),
1694 1.42 pk (struct disklabel *)NULL);
1695 1.42 pk
1696 1.42 pk printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1697 1.42 pk NE7_ST0BITS, bits, sizeof(bits)));
1698 1.42 pk printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1699 1.42 pk NE7_ST1BITS, bits, sizeof(bits)));
1700 1.42 pk printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1701 1.42 pk NE7_ST2BITS, bits, sizeof(bits)));
1702 1.42 pk printf(" cyl %d head %d sec %d)\n",
1703 1.42 pk fdc->sc_status[3], fdc->sc_status[4],
1704 1.42 pk fdc->sc_status[5]);
1705 1.42 pk }
1706 1.1 pk
1707 1.1 pk bp->b_flags |= B_ERROR;
1708 1.1 pk bp->b_error = EIO;
1709 1.1 pk fdfinish(fd, bp);
1710 1.1 pk }
1711 1.1 pk fdc->sc_errors++;
1712 1.1 pk }
1713 1.1 pk
1714 1.1 pk int
1715 1.1 pk fdsize(dev)
1716 1.1 pk dev_t dev;
1717 1.1 pk {
1718 1.1 pk
1719 1.1 pk /* Swapping to floppies would not make sense. */
1720 1.42 pk return (-1);
1721 1.1 pk }
1722 1.1 pk
1723 1.1 pk int
1724 1.24 christos fddump(dev, blkno, va, size)
1725 1.24 christos dev_t dev;
1726 1.24 christos daddr_t blkno;
1727 1.24 christos caddr_t va;
1728 1.24 christos size_t size;
1729 1.1 pk {
1730 1.1 pk
1731 1.1 pk /* Not implemented. */
1732 1.42 pk return (EINVAL);
1733 1.1 pk }
1734 1.1 pk
1735 1.1 pk int
1736 1.24 christos fdioctl(dev, cmd, addr, flag, p)
1737 1.1 pk dev_t dev;
1738 1.1 pk u_long cmd;
1739 1.1 pk caddr_t addr;
1740 1.1 pk int flag;
1741 1.24 christos struct proc *p;
1742 1.1 pk {
1743 1.70 pk struct fd_softc *fd;
1744 1.70 pk struct fdc_softc *fdc;
1745 1.42 pk struct fdformat_parms *form_parms;
1746 1.42 pk struct fdformat_cmd *form_cmd;
1747 1.42 pk struct ne7_fd_formb fd_formb;
1748 1.42 pk int il[FD_MAX_NSEC + 1];
1749 1.70 pk int unit;
1750 1.42 pk int i, j;
1751 1.1 pk int error;
1752 1.1 pk
1753 1.70 pk unit = FDUNIT(dev);
1754 1.70 pk if (unit >= fd_cd.cd_ndevs)
1755 1.70 pk return (ENXIO);
1756 1.70 pk
1757 1.70 pk fd = fd_cd.cd_devs[FDUNIT(dev)];
1758 1.70 pk fdc = (struct fdc_softc *)fd->sc_dv.dv_parent;
1759 1.70 pk
1760 1.1 pk switch (cmd) {
1761 1.1 pk case DIOCGDINFO:
1762 1.16 thorpej *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1763 1.1 pk return 0;
1764 1.1 pk
1765 1.1 pk case DIOCWLABEL:
1766 1.1 pk if ((flag & FWRITE) == 0)
1767 1.1 pk return EBADF;
1768 1.1 pk /* XXX do something */
1769 1.42 pk return (0);
1770 1.1 pk
1771 1.1 pk case DIOCWDINFO:
1772 1.1 pk if ((flag & FWRITE) == 0)
1773 1.42 pk return (EBADF);
1774 1.1 pk
1775 1.16 thorpej error = setdisklabel(fd->sc_dk.dk_label,
1776 1.11 pk (struct disklabel *)addr, 0,
1777 1.16 thorpej fd->sc_dk.dk_cpulabel);
1778 1.1 pk if (error)
1779 1.42 pk return (error);
1780 1.1 pk
1781 1.11 pk error = writedisklabel(dev, fdstrategy,
1782 1.16 thorpej fd->sc_dk.dk_label,
1783 1.16 thorpej fd->sc_dk.dk_cpulabel);
1784 1.42 pk return (error);
1785 1.21 thorpej
1786 1.21 thorpej case DIOCLOCK:
1787 1.21 thorpej /*
1788 1.21 thorpej * Nothing to do here, really.
1789 1.21 thorpej */
1790 1.42 pk return (0);
1791 1.1 pk
1792 1.13 pk case DIOCEJECT:
1793 1.66 bouyer if (*(int *)addr == 0) {
1794 1.66 bouyer int part = DISKPART(dev);
1795 1.66 bouyer /*
1796 1.66 bouyer * Don't force eject: check that we are the only
1797 1.66 bouyer * partition open. If so, unlock it.
1798 1.66 bouyer */
1799 1.66 bouyer if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1800 1.66 bouyer fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1801 1.66 bouyer fd->sc_dk.dk_openmask) {
1802 1.66 bouyer return (EBUSY);
1803 1.66 bouyer }
1804 1.66 bouyer }
1805 1.66 bouyer /* FALLTHROUGH */
1806 1.66 bouyer case ODIOCEJECT:
1807 1.50 pk fd_do_eject(fd);
1808 1.42 pk return (0);
1809 1.42 pk
1810 1.42 pk case FDIOCGETFORMAT:
1811 1.42 pk form_parms = (struct fdformat_parms *)addr;
1812 1.42 pk form_parms->fdformat_version = FDFORMAT_VERSION;
1813 1.42 pk form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1814 1.49 pk form_parms->ncyl = fd->sc_type->cylinders;
1815 1.42 pk form_parms->nspt = fd->sc_type->sectrac;
1816 1.42 pk form_parms->ntrk = fd->sc_type->heads;
1817 1.42 pk form_parms->stepspercyl = fd->sc_type->step;
1818 1.42 pk form_parms->gaplen = fd->sc_type->gap2;
1819 1.42 pk form_parms->fillbyte = fd->sc_type->fillbyte;
1820 1.42 pk form_parms->interleave = fd->sc_type->interleave;
1821 1.42 pk switch (fd->sc_type->rate) {
1822 1.42 pk case FDC_500KBPS:
1823 1.42 pk form_parms->xfer_rate = 500 * 1024;
1824 1.42 pk break;
1825 1.42 pk case FDC_300KBPS:
1826 1.42 pk form_parms->xfer_rate = 300 * 1024;
1827 1.42 pk break;
1828 1.42 pk case FDC_250KBPS:
1829 1.42 pk form_parms->xfer_rate = 250 * 1024;
1830 1.42 pk break;
1831 1.42 pk default:
1832 1.42 pk return (EINVAL);
1833 1.42 pk }
1834 1.43 pk return (0);
1835 1.42 pk
1836 1.42 pk case FDIOCSETFORMAT:
1837 1.42 pk if ((flag & FWRITE) == 0)
1838 1.42 pk return (EBADF); /* must be opened for writing */
1839 1.42 pk
1840 1.42 pk form_parms = (struct fdformat_parms *)addr;
1841 1.42 pk if (form_parms->fdformat_version != FDFORMAT_VERSION)
1842 1.42 pk return (EINVAL);/* wrong version of formatting prog */
1843 1.42 pk
1844 1.42 pk i = form_parms->nbps >> 7;
1845 1.42 pk if ((form_parms->nbps & 0x7f) || ffs(i) == 0 ||
1846 1.42 pk i & ~(1 << (ffs(i)-1)))
1847 1.42 pk /* not a power-of-two multiple of 128 */
1848 1.42 pk return (EINVAL);
1849 1.42 pk
1850 1.42 pk switch (form_parms->xfer_rate) {
1851 1.42 pk case 500 * 1024:
1852 1.42 pk fd->sc_type->rate = FDC_500KBPS;
1853 1.42 pk break;
1854 1.42 pk case 300 * 1024:
1855 1.42 pk fd->sc_type->rate = FDC_300KBPS;
1856 1.42 pk break;
1857 1.42 pk case 250 * 1024:
1858 1.42 pk fd->sc_type->rate = FDC_250KBPS;
1859 1.42 pk break;
1860 1.42 pk default:
1861 1.42 pk return (EINVAL);
1862 1.42 pk }
1863 1.42 pk
1864 1.42 pk if (form_parms->nspt > FD_MAX_NSEC ||
1865 1.42 pk form_parms->fillbyte > 0xff ||
1866 1.42 pk form_parms->interleave > 0xff)
1867 1.42 pk return EINVAL;
1868 1.42 pk fd->sc_type->sectrac = form_parms->nspt;
1869 1.42 pk if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1870 1.42 pk return EINVAL;
1871 1.42 pk fd->sc_type->heads = form_parms->ntrk;
1872 1.42 pk fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1873 1.42 pk fd->sc_type->secsize = ffs(i)-1;
1874 1.42 pk fd->sc_type->gap2 = form_parms->gaplen;
1875 1.49 pk fd->sc_type->cylinders = form_parms->ncyl;
1876 1.42 pk fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1877 1.42 pk form_parms->nbps / DEV_BSIZE;
1878 1.42 pk fd->sc_type->step = form_parms->stepspercyl;
1879 1.42 pk fd->sc_type->fillbyte = form_parms->fillbyte;
1880 1.42 pk fd->sc_type->interleave = form_parms->interleave;
1881 1.49 pk return (0);
1882 1.16 thorpej
1883 1.42 pk case FDIOCFORMAT_TRACK:
1884 1.42 pk if((flag & FWRITE) == 0)
1885 1.42 pk /* must be opened for writing */
1886 1.42 pk return (EBADF);
1887 1.42 pk form_cmd = (struct fdformat_cmd *)addr;
1888 1.42 pk if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1889 1.42 pk /* wrong version of formatting prog */
1890 1.42 pk return (EINVAL);
1891 1.42 pk
1892 1.42 pk if (form_cmd->head >= fd->sc_type->heads ||
1893 1.49 pk form_cmd->cylinder >= fd->sc_type->cylinders) {
1894 1.42 pk return (EINVAL);
1895 1.42 pk }
1896 1.42 pk
1897 1.42 pk fd_formb.head = form_cmd->head;
1898 1.42 pk fd_formb.cyl = form_cmd->cylinder;
1899 1.42 pk fd_formb.transfer_rate = fd->sc_type->rate;
1900 1.42 pk fd_formb.fd_formb_secshift = fd->sc_type->secsize;
1901 1.42 pk fd_formb.fd_formb_nsecs = fd->sc_type->sectrac;
1902 1.42 pk fd_formb.fd_formb_gaplen = fd->sc_type->gap2;
1903 1.42 pk fd_formb.fd_formb_fillbyte = fd->sc_type->fillbyte;
1904 1.42 pk
1905 1.49 pk bzero(il, sizeof il);
1906 1.42 pk for (j = 0, i = 1; i <= fd_formb.fd_formb_nsecs; i++) {
1907 1.49 pk while (il[(j%fd_formb.fd_formb_nsecs) + 1])
1908 1.42 pk j++;
1909 1.49 pk il[(j%fd_formb.fd_formb_nsecs) + 1] = i;
1910 1.42 pk j += fd->sc_type->interleave;
1911 1.42 pk }
1912 1.42 pk for (i = 0; i < fd_formb.fd_formb_nsecs; i++) {
1913 1.42 pk fd_formb.fd_formb_cylno(i) = form_cmd->cylinder;
1914 1.42 pk fd_formb.fd_formb_headno(i) = form_cmd->head;
1915 1.42 pk fd_formb.fd_formb_secno(i) = il[i+1];
1916 1.42 pk fd_formb.fd_formb_secsize(i) = fd->sc_type->secsize;
1917 1.42 pk }
1918 1.42 pk
1919 1.42 pk return fdformat(dev, &fd_formb, p);
1920 1.42 pk
1921 1.42 pk case FDIOCGETOPTS: /* get drive options */
1922 1.42 pk *(int *)addr = fd->sc_opts;
1923 1.42 pk return (0);
1924 1.42 pk
1925 1.42 pk case FDIOCSETOPTS: /* set drive options */
1926 1.42 pk fd->sc_opts = *(int *)addr;
1927 1.42 pk return (0);
1928 1.42 pk
1929 1.1 pk #ifdef DEBUG
1930 1.1 pk case _IO('f', 100):
1931 1.1 pk out_fdc(fdc, NE7CMD_DUMPREG);
1932 1.1 pk fdcresult(fdc);
1933 1.70 pk printf("fdc: dumpreg(%d regs): <", fdc->sc_nstat);
1934 1.1 pk for (i = 0; i < fdc->sc_nstat; i++)
1935 1.52 fair printf(" 0x%x", fdc->sc_status[i]);
1936 1.39 christos printf(">\n");
1937 1.70 pk return (0);
1938 1.1 pk
1939 1.1 pk case _IOW('f', 101, int):
1940 1.70 pk fdc->sc_cfg &= ~CFG_THRHLD_MASK;
1941 1.70 pk fdc->sc_cfg |= (*(int *)addr & CFG_THRHLD_MASK);
1942 1.70 pk fdconf(fdc);
1943 1.42 pk return (0);
1944 1.70 pk
1945 1.1 pk case _IO('f', 102):
1946 1.1 pk out_fdc(fdc, NE7CMD_SENSEI);
1947 1.1 pk fdcresult(fdc);
1948 1.70 pk printf("fdc: sensei(%d regs): <", fdc->sc_nstat);
1949 1.1 pk for (i=0; i< fdc->sc_nstat; i++)
1950 1.39 christos printf(" 0x%x", fdc->sc_status[i]);
1951 1.39 christos printf(">\n");
1952 1.42 pk return (0);
1953 1.1 pk #endif
1954 1.1 pk default:
1955 1.42 pk return (ENOTTY);
1956 1.1 pk }
1957 1.1 pk
1958 1.1 pk #ifdef DIAGNOSTIC
1959 1.1 pk panic("fdioctl: impossible");
1960 1.1 pk #endif
1961 1.19 thorpej }
1962 1.19 thorpej
1963 1.42 pk int
1964 1.42 pk fdformat(dev, finfo, p)
1965 1.42 pk dev_t dev;
1966 1.42 pk struct ne7_fd_formb *finfo;
1967 1.42 pk struct proc *p;
1968 1.42 pk {
1969 1.42 pk int rv = 0, s;
1970 1.42 pk struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1971 1.42 pk struct fd_type *type = fd->sc_type;
1972 1.42 pk struct buf *bp;
1973 1.42 pk
1974 1.42 pk /* set up a buffer header for fdstrategy() */
1975 1.42 pk bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1976 1.42 pk if (bp == 0)
1977 1.42 pk return (ENOBUFS);
1978 1.42 pk
1979 1.42 pk PHOLD(p);
1980 1.42 pk bzero((void *)bp, sizeof(struct buf));
1981 1.42 pk bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1982 1.42 pk bp->b_proc = p;
1983 1.42 pk bp->b_dev = dev;
1984 1.42 pk
1985 1.42 pk /*
1986 1.49 pk * Calculate a fake blkno, so fdstrategy() would initiate a
1987 1.49 pk * seek to the requested cylinder.
1988 1.42 pk */
1989 1.53 pk bp->b_blkno = ((finfo->cyl * (type->sectrac * type->heads)
1990 1.53 pk + finfo->head * type->sectrac) * FD_BSIZE(fd))
1991 1.53 pk / DEV_BSIZE;
1992 1.42 pk
1993 1.42 pk bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1994 1.42 pk bp->b_data = (caddr_t)finfo;
1995 1.42 pk
1996 1.42 pk #ifdef FD_DEBUG
1997 1.42 pk if (fdc_debug)
1998 1.52 fair printf("fdformat: blkno 0x%x count %ld\n",
1999 1.42 pk bp->b_blkno, bp->b_bcount);
2000 1.42 pk #endif
2001 1.42 pk
2002 1.42 pk /* now do the format */
2003 1.42 pk fdstrategy(bp);
2004 1.42 pk
2005 1.42 pk /* ...and wait for it to complete */
2006 1.42 pk s = splbio();
2007 1.42 pk while (!(bp->b_flags & B_DONE)) {
2008 1.42 pk rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
2009 1.42 pk if (rv == EWOULDBLOCK)
2010 1.42 pk break;
2011 1.42 pk }
2012 1.42 pk splx(s);
2013 1.42 pk
2014 1.42 pk if (rv == EWOULDBLOCK) {
2015 1.42 pk /* timed out */
2016 1.42 pk rv = EIO;
2017 1.42 pk biodone(bp);
2018 1.42 pk }
2019 1.42 pk if (bp->b_flags & B_ERROR) {
2020 1.42 pk rv = bp->b_error;
2021 1.42 pk }
2022 1.42 pk PRELE(p);
2023 1.42 pk free(bp, M_TEMP);
2024 1.42 pk return (rv);
2025 1.42 pk }
2026 1.42 pk
2027 1.19 thorpej void
2028 1.19 thorpej fdgetdisklabel(dev)
2029 1.19 thorpej dev_t dev;
2030 1.19 thorpej {
2031 1.19 thorpej int unit = FDUNIT(dev), i;
2032 1.26 thorpej struct fd_softc *fd = fd_cd.cd_devs[unit];
2033 1.19 thorpej struct disklabel *lp = fd->sc_dk.dk_label;
2034 1.19 thorpej struct cpu_disklabel *clp = fd->sc_dk.dk_cpulabel;
2035 1.19 thorpej
2036 1.19 thorpej bzero(lp, sizeof(struct disklabel));
2037 1.19 thorpej bzero(lp, sizeof(struct cpu_disklabel));
2038 1.19 thorpej
2039 1.19 thorpej lp->d_type = DTYPE_FLOPPY;
2040 1.53 pk lp->d_secsize = FD_BSIZE(fd);
2041 1.19 thorpej lp->d_secpercyl = fd->sc_type->seccyl;
2042 1.19 thorpej lp->d_nsectors = fd->sc_type->sectrac;
2043 1.49 pk lp->d_ncylinders = fd->sc_type->cylinders;
2044 1.19 thorpej lp->d_ntracks = fd->sc_type->heads; /* Go figure... */
2045 1.19 thorpej lp->d_rpm = 3600; /* XXX like it matters... */
2046 1.19 thorpej
2047 1.19 thorpej strncpy(lp->d_typename, "floppy", sizeof(lp->d_typename));
2048 1.19 thorpej strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
2049 1.19 thorpej lp->d_interleave = 1;
2050 1.19 thorpej
2051 1.19 thorpej lp->d_partitions[RAW_PART].p_offset = 0;
2052 1.19 thorpej lp->d_partitions[RAW_PART].p_size = lp->d_secpercyl * lp->d_ncylinders;
2053 1.19 thorpej lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
2054 1.19 thorpej lp->d_npartitions = RAW_PART + 1;
2055 1.19 thorpej
2056 1.19 thorpej lp->d_magic = DISKMAGIC;
2057 1.19 thorpej lp->d_magic2 = DISKMAGIC;
2058 1.19 thorpej lp->d_checksum = dkcksum(lp);
2059 1.19 thorpej
2060 1.19 thorpej /*
2061 1.19 thorpej * Call the generic disklabel extraction routine. If there's
2062 1.19 thorpej * not a label there, fake it.
2063 1.19 thorpej */
2064 1.19 thorpej if (readdisklabel(dev, fdstrategy, lp, clp) != NULL) {
2065 1.19 thorpej strncpy(lp->d_packname, "default label",
2066 1.19 thorpej sizeof(lp->d_packname));
2067 1.19 thorpej /*
2068 1.19 thorpej * Reset the partition info; it might have gotten
2069 1.19 thorpej * trashed in readdisklabel().
2070 1.19 thorpej *
2071 1.19 thorpej * XXX Why do we have to do this? readdisklabel()
2072 1.19 thorpej * should be safe...
2073 1.19 thorpej */
2074 1.19 thorpej for (i = 0; i < MAXPARTITIONS; ++i) {
2075 1.19 thorpej lp->d_partitions[i].p_offset = 0;
2076 1.19 thorpej if (i == RAW_PART) {
2077 1.19 thorpej lp->d_partitions[i].p_size =
2078 1.19 thorpej lp->d_secpercyl * lp->d_ncylinders;
2079 1.19 thorpej lp->d_partitions[i].p_fstype = FS_BSDFFS;
2080 1.19 thorpej } else {
2081 1.19 thorpej lp->d_partitions[i].p_size = 0;
2082 1.19 thorpej lp->d_partitions[i].p_fstype = FS_UNUSED;
2083 1.19 thorpej }
2084 1.19 thorpej }
2085 1.19 thorpej lp->d_npartitions = RAW_PART + 1;
2086 1.19 thorpej }
2087 1.19 thorpej }
2088 1.19 thorpej
2089 1.19 thorpej void
2090 1.50 pk fd_do_eject(fd)
2091 1.50 pk struct fd_softc *fd;
2092 1.19 thorpej {
2093 1.50 pk struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
2094 1.50 pk
2095 1.49 pk if (CPU_ISSUN4C) {
2096 1.49 pk auxregbisc(AUXIO4C_FDS, AUXIO4C_FEJ);
2097 1.49 pk delay(10);
2098 1.49 pk auxregbisc(AUXIO4C_FEJ, AUXIO4C_FDS);
2099 1.50 pk return;
2100 1.49 pk }
2101 1.50 pk if (CPU_ISSUN4M && (fdc->sc_flags & FDC_82077)) {
2102 1.70 pk bus_space_tag_t t = fdc->sc_bustag;
2103 1.70 pk bus_space_handle_t h = fdc->sc_handle;
2104 1.70 pk u_int8_t dor = FDO_FRST | FDO_FDMAEN | FDO_MOEN(0);
2105 1.70 pk
2106 1.70 pk bus_space_write_1(t, h, fdc->sc_reg_dor, dor | FDO_EJ);
2107 1.50 pk delay(10);
2108 1.70 pk bus_space_write_1(t, h, fdc->sc_reg_dor, FDO_FRST | FDO_DS);
2109 1.50 pk return;
2110 1.49 pk }
2111 1.19 thorpej }
2112 1.19 thorpej
2113 1.45 pk #ifdef MEMORY_DISK_HOOKS
2114 1.45 pk int fd_read_md_image __P((size_t *, caddr_t *));
2115 1.36 pk #endif
2116 1.36 pk
2117 1.19 thorpej /* ARGSUSED */
2118 1.19 thorpej void
2119 1.19 thorpej fd_mountroot_hook(dev)
2120 1.19 thorpej struct device *dev;
2121 1.19 thorpej {
2122 1.19 thorpej int c;
2123 1.19 thorpej
2124 1.50 pk fd_do_eject((struct fd_softc *)dev);
2125 1.39 christos printf("Insert filesystem floppy and press return.");
2126 1.19 thorpej for (;;) {
2127 1.19 thorpej c = cngetc();
2128 1.19 thorpej if ((c == '\r') || (c == '\n')) {
2129 1.39 christos printf("\n");
2130 1.36 pk break;
2131 1.36 pk }
2132 1.36 pk }
2133 1.36 pk }
2134 1.36 pk
2135 1.45 pk #ifdef MEMORY_DISK_HOOKS
2136 1.36 pk
2137 1.36 pk #define FDMICROROOTSIZE ((2*18*80) << DEV_BSHIFT)
2138 1.36 pk
2139 1.36 pk int
2140 1.45 pk fd_read_md_image(sizep, addrp)
2141 1.36 pk size_t *sizep;
2142 1.36 pk caddr_t *addrp;
2143 1.36 pk {
2144 1.36 pk struct buf buf, *bp = &buf;
2145 1.36 pk dev_t dev;
2146 1.36 pk off_t offset;
2147 1.36 pk caddr_t addr;
2148 1.36 pk
2149 1.36 pk dev = makedev(54,0); /* XXX */
2150 1.36 pk
2151 1.36 pk MALLOC(addr, caddr_t, FDMICROROOTSIZE, M_DEVBUF, M_WAITOK);
2152 1.36 pk *addrp = addr;
2153 1.36 pk
2154 1.36 pk if (fdopen(dev, 0, S_IFCHR, NULL))
2155 1.36 pk panic("fd: mountroot: fdopen");
2156 1.36 pk
2157 1.36 pk offset = 0;
2158 1.36 pk
2159 1.36 pk for (;;) {
2160 1.36 pk bp->b_dev = dev;
2161 1.36 pk bp->b_error = 0;
2162 1.36 pk bp->b_resid = 0;
2163 1.36 pk bp->b_proc = NULL;
2164 1.36 pk bp->b_flags = B_BUSY | B_PHYS | B_RAW | B_READ;
2165 1.36 pk bp->b_blkno = btodb(offset);
2166 1.36 pk bp->b_bcount = DEV_BSIZE;
2167 1.36 pk bp->b_data = addr;
2168 1.36 pk fdstrategy(bp);
2169 1.36 pk while ((bp->b_flags & B_DONE) == 0) {
2170 1.36 pk tsleep((caddr_t)bp, PRIBIO + 1, "physio", 0);
2171 1.19 thorpej }
2172 1.36 pk if (bp->b_error)
2173 1.36 pk panic("fd: mountroot: fdread error %d", bp->b_error);
2174 1.36 pk
2175 1.36 pk if (bp->b_resid != 0)
2176 1.36 pk break;
2177 1.36 pk
2178 1.36 pk addr += DEV_BSIZE;
2179 1.36 pk offset += DEV_BSIZE;
2180 1.36 pk if (offset + DEV_BSIZE > FDMICROROOTSIZE)
2181 1.36 pk break;
2182 1.19 thorpej }
2183 1.36 pk (void)fdclose(dev, 0, S_IFCHR, NULL);
2184 1.36 pk *sizep = offset;
2185 1.50 pk fd_do_eject(fd_cd.cd_devs[FDUNIT(dev)]);
2186 1.42 pk return (0);
2187 1.1 pk }
2188 1.36 pk #endif
2189