hdfd.c revision 1.28.8.3 1 1.28.8.3 nathanw /* $NetBSD: hdfd.c,v 1.28.8.3 2002/08/13 02:18:01 nathanw Exp $ */
2 1.28.8.2 nathanw
3 1.28.8.2 nathanw /*-
4 1.28.8.2 nathanw * Copyright (c) 1996 Leo Weppelman
5 1.28.8.2 nathanw * Copyright (c) 1993, 1994, 1995, 1996
6 1.28.8.2 nathanw * Charles M. Hannum. All rights reserved.
7 1.28.8.2 nathanw * Copyright (c) 1990 The Regents of the University of California.
8 1.28.8.2 nathanw * All rights reserved.
9 1.28.8.2 nathanw *
10 1.28.8.2 nathanw * This code is derived from software contributed to Berkeley by
11 1.28.8.2 nathanw * Don Ahn.
12 1.28.8.2 nathanw *
13 1.28.8.2 nathanw * Redistribution and use in source and binary forms, with or without
14 1.28.8.2 nathanw * modification, are permitted provided that the following conditions
15 1.28.8.2 nathanw * are met:
16 1.28.8.2 nathanw * 1. Redistributions of source code must retain the above copyright
17 1.28.8.2 nathanw * notice, this list of conditions and the following disclaimer.
18 1.28.8.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
19 1.28.8.2 nathanw * notice, this list of conditions and the following disclaimer in the
20 1.28.8.2 nathanw * documentation and/or other materials provided with the distribution.
21 1.28.8.2 nathanw * 3. All advertising materials mentioning features or use of this software
22 1.28.8.2 nathanw * must display the following acknowledgement:
23 1.28.8.2 nathanw * This product includes software developed by the University of
24 1.28.8.2 nathanw * California, Berkeley and its contributors.
25 1.28.8.2 nathanw * 4. Neither the name of the University nor the names of its contributors
26 1.28.8.2 nathanw * may be used to endorse or promote products derived from this software
27 1.28.8.2 nathanw * without specific prior written permission.
28 1.28.8.2 nathanw *
29 1.28.8.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 1.28.8.2 nathanw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 1.28.8.2 nathanw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 1.28.8.2 nathanw * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 1.28.8.2 nathanw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 1.28.8.2 nathanw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 1.28.8.2 nathanw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 1.28.8.2 nathanw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 1.28.8.2 nathanw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 1.28.8.2 nathanw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 1.28.8.2 nathanw * SUCH DAMAGE.
40 1.28.8.2 nathanw *
41 1.28.8.2 nathanw * @(#)fd.c 7.4 (Berkeley) 5/25/91
42 1.28.8.2 nathanw */
43 1.28.8.2 nathanw
44 1.28.8.2 nathanw /*
45 1.28.8.2 nathanw * Floppy formatting facilities merged from FreeBSD fd.c driver:
46 1.28.8.2 nathanw * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
47 1.28.8.2 nathanw * which carries the same copyright/redistribution notice as shown above with
48 1.28.8.2 nathanw * the addition of the following statement before the "Redistribution and
49 1.28.8.2 nathanw * use ..." clause:
50 1.28.8.2 nathanw *
51 1.28.8.2 nathanw * Copyright (c) 1993, 1994 by
52 1.28.8.2 nathanw * jc (at) irbs.UUCP (John Capo)
53 1.28.8.2 nathanw * vak (at) zebub.msk.su (Serge Vakulenko)
54 1.28.8.2 nathanw * ache (at) astral.msk.su (Andrew A. Chernov)
55 1.28.8.2 nathanw *
56 1.28.8.2 nathanw * Copyright (c) 1993, 1994, 1995 by
57 1.28.8.2 nathanw * joerg_wunsch (at) uriah.sax.de (Joerg Wunsch)
58 1.28.8.2 nathanw * dufault (at) hda.com (Peter Dufault)
59 1.28.8.2 nathanw */
60 1.28.8.2 nathanw
61 1.28.8.2 nathanw #include "opt_ddb.h"
62 1.28.8.2 nathanw
63 1.28.8.2 nathanw #include <sys/param.h>
64 1.28.8.2 nathanw #include <sys/systm.h>
65 1.28.8.2 nathanw #include <sys/callout.h>
66 1.28.8.2 nathanw #include <sys/kernel.h>
67 1.28.8.2 nathanw #include <sys/file.h>
68 1.28.8.2 nathanw #include <sys/ioctl.h>
69 1.28.8.2 nathanw #include <sys/device.h>
70 1.28.8.2 nathanw #include <sys/disklabel.h>
71 1.28.8.2 nathanw #include <sys/dkstat.h>
72 1.28.8.2 nathanw #include <sys/disk.h>
73 1.28.8.2 nathanw #include <sys/buf.h>
74 1.28.8.2 nathanw #include <sys/malloc.h>
75 1.28.8.2 nathanw #include <sys/uio.h>
76 1.28.8.2 nathanw #include <sys/syslog.h>
77 1.28.8.2 nathanw #include <sys/queue.h>
78 1.28.8.2 nathanw #include <sys/proc.h>
79 1.28.8.2 nathanw #include <sys/fdio.h>
80 1.28.8.2 nathanw #include <sys/conf.h>
81 1.28.8.2 nathanw #include <sys/device.h>
82 1.28.8.2 nathanw
83 1.28.8.2 nathanw #include <uvm/uvm_extern.h>
84 1.28.8.2 nathanw
85 1.28.8.2 nathanw #include <machine/cpu.h>
86 1.28.8.2 nathanw #include <machine/bus.h>
87 1.28.8.2 nathanw #include <machine/iomap.h>
88 1.28.8.2 nathanw #include <machine/mfp.h>
89 1.28.8.2 nathanw
90 1.28.8.2 nathanw #include <atari/dev/hdfdreg.h>
91 1.28.8.2 nathanw #include <atari/atari/intr.h>
92 1.28.8.2 nathanw #include <atari/atari/device.h>
93 1.28.8.2 nathanw
94 1.28.8.2 nathanw #include "locators.h"
95 1.28.8.2 nathanw
96 1.28.8.2 nathanw /*
97 1.28.8.2 nathanw * {b,c}devsw[] function prototypes
98 1.28.8.2 nathanw */
99 1.28.8.2 nathanw dev_type_open(fdopen);
100 1.28.8.2 nathanw dev_type_close(fdclose);
101 1.28.8.2 nathanw dev_type_read(fdread);
102 1.28.8.2 nathanw dev_type_write(fdwrite);
103 1.28.8.2 nathanw dev_type_ioctl(fdioctl);
104 1.28.8.2 nathanw dev_type_size(fdsize);
105 1.28.8.2 nathanw dev_type_dump(fddump);
106 1.28.8.2 nathanw
107 1.28.8.2 nathanw volatile u_char *fdio_addr;
108 1.28.8.2 nathanw
109 1.28.8.2 nathanw #define wrt_fdc_reg(reg, val) { fdio_addr[reg] = val; }
110 1.28.8.2 nathanw #define rd_fdc_reg(reg) ( fdio_addr[reg] )
111 1.28.8.2 nathanw
112 1.28.8.2 nathanw #define fdc_ienable() MFP2->mf_ierb |= IB_DCHG;
113 1.28.8.2 nathanw
114 1.28.8.2 nathanw /*
115 1.28.8.2 nathanw * Interface to the pseudo-dma handler
116 1.28.8.2 nathanw */
117 1.28.8.2 nathanw void fddma_intr(void);
118 1.28.8.2 nathanw caddr_t fddmaaddr = NULL;
119 1.28.8.2 nathanw int fddmalen = 0;
120 1.28.8.2 nathanw
121 1.28.8.2 nathanw extern void mfp_hdfd_nf __P((void)), mfp_hdfd_fifo __P((void));
122 1.28.8.2 nathanw
123 1.28.8.2 nathanw /*
124 1.28.8.2 nathanw * Argument to fdcintr.....
125 1.28.8.2 nathanw */
126 1.28.8.2 nathanw static void *intr_arg = NULL; /* XXX: arg. to intr_establish() */
127 1.28.8.2 nathanw
128 1.28.8.2 nathanw
129 1.28.8.2 nathanw
130 1.28.8.2 nathanw #define FDUNIT(dev) (minor(dev) / 8)
131 1.28.8.2 nathanw #define FDTYPE(dev) (minor(dev) % 8)
132 1.28.8.2 nathanw
133 1.28.8.2 nathanw /* XXX misuse a flag to identify format operation */
134 1.28.8.2 nathanw #define B_FORMAT B_XXX
135 1.28.8.2 nathanw
136 1.28.8.2 nathanw enum fdc_state {
137 1.28.8.2 nathanw DEVIDLE = 0,
138 1.28.8.2 nathanw MOTORWAIT,
139 1.28.8.2 nathanw DOSEEK,
140 1.28.8.2 nathanw SEEKWAIT,
141 1.28.8.2 nathanw SEEKTIMEDOUT,
142 1.28.8.2 nathanw SEEKCOMPLETE,
143 1.28.8.2 nathanw DOIO,
144 1.28.8.2 nathanw IOCOMPLETE,
145 1.28.8.2 nathanw IOTIMEDOUT,
146 1.28.8.2 nathanw DORESET,
147 1.28.8.2 nathanw RESETCOMPLETE,
148 1.28.8.2 nathanw RESETTIMEDOUT,
149 1.28.8.2 nathanw DORECAL,
150 1.28.8.2 nathanw RECALWAIT,
151 1.28.8.2 nathanw RECALTIMEDOUT,
152 1.28.8.2 nathanw RECALCOMPLETE,
153 1.28.8.2 nathanw };
154 1.28.8.2 nathanw
155 1.28.8.2 nathanw /* software state, per controller */
156 1.28.8.2 nathanw struct fdc_softc {
157 1.28.8.2 nathanw struct device sc_dev; /* boilerplate */
158 1.28.8.2 nathanw
159 1.28.8.2 nathanw struct callout sc_timo_ch; /* timeout callout */
160 1.28.8.2 nathanw struct callout sc_intr_ch; /* pseudo-intr callout */
161 1.28.8.2 nathanw
162 1.28.8.2 nathanw struct fd_softc *sc_fd[4]; /* pointers to children */
163 1.28.8.2 nathanw TAILQ_HEAD(drivehead, fd_softc) sc_drives;
164 1.28.8.2 nathanw enum fdc_state sc_state;
165 1.28.8.2 nathanw int sc_errors; /* number of retries so far */
166 1.28.8.2 nathanw int sc_overruns; /* number of overruns so far */
167 1.28.8.2 nathanw u_char sc_status[7]; /* copy of registers */
168 1.28.8.2 nathanw };
169 1.28.8.2 nathanw
170 1.28.8.2 nathanw /* controller driver configuration */
171 1.28.8.2 nathanw int fdcprobe __P((struct device *, struct cfdata *, void *));
172 1.28.8.2 nathanw int fdprint __P((void *, const char *));
173 1.28.8.2 nathanw void fdcattach __P((struct device *, struct device *, void *));
174 1.28.8.2 nathanw
175 1.28.8.2 nathanw struct cfattach fdc_ca = {
176 1.28.8.2 nathanw sizeof(struct fdc_softc), fdcprobe, fdcattach
177 1.28.8.2 nathanw };
178 1.28.8.2 nathanw
179 1.28.8.2 nathanw /*
180 1.28.8.2 nathanw * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
181 1.28.8.2 nathanw * we tell them apart.
182 1.28.8.2 nathanw */
183 1.28.8.2 nathanw struct fd_type {
184 1.28.8.2 nathanw int sectrac; /* sectors per track */
185 1.28.8.2 nathanw int heads; /* number of heads */
186 1.28.8.2 nathanw int seccyl; /* sectors per cylinder */
187 1.28.8.2 nathanw int secsize; /* size code for sectors */
188 1.28.8.2 nathanw int datalen; /* data len when secsize = 0 */
189 1.28.8.2 nathanw int steprate; /* step rate and head unload time */
190 1.28.8.2 nathanw int gap1; /* gap len between sectors */
191 1.28.8.2 nathanw int gap2; /* formatting gap */
192 1.28.8.2 nathanw int tracks; /* total num of tracks */
193 1.28.8.2 nathanw int size; /* size of disk in sectors */
194 1.28.8.2 nathanw int step; /* steps per cylinder */
195 1.28.8.2 nathanw int rate; /* transfer speed code */
196 1.28.8.2 nathanw u_char fillbyte; /* format fill byte */
197 1.28.8.2 nathanw u_char interleave; /* interleave factor (formatting) */
198 1.28.8.2 nathanw char *name;
199 1.28.8.2 nathanw };
200 1.28.8.2 nathanw
201 1.28.8.2 nathanw /*
202 1.28.8.2 nathanw * The order of entries in the following table is important -- BEWARE!
203 1.28.8.2 nathanw * The order of the types is the same as for the TT/Falcon....
204 1.28.8.2 nathanw */
205 1.28.8.2 nathanw struct fd_type fd_types[] = {
206 1.28.8.2 nathanw /* 360kB in 720kB drive */
207 1.28.8.2 nathanw { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_125KBPS,0xf6,1,"360KB" },
208 1.28.8.2 nathanw /* 3.5" 720kB diskette */
209 1.28.8.2 nathanw { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_125KBPS,0xf6,1,"720KB" },
210 1.28.8.2 nathanw /* 1.44MB diskette */
211 1.28.8.2 nathanw { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_250KBPS,0xf6,1,"1.44MB" },
212 1.28.8.2 nathanw };
213 1.28.8.2 nathanw
214 1.28.8.2 nathanw /* software state, per disk (with up to 4 disks per ctlr) */
215 1.28.8.2 nathanw struct fd_softc {
216 1.28.8.2 nathanw struct device sc_dev;
217 1.28.8.2 nathanw struct disk sc_dk;
218 1.28.8.2 nathanw
219 1.28.8.2 nathanw struct fd_type *sc_deftype; /* default type descriptor */
220 1.28.8.2 nathanw struct fd_type *sc_type; /* current type descriptor */
221 1.28.8.2 nathanw
222 1.28.8.2 nathanw struct callout sc_motoron_ch;
223 1.28.8.2 nathanw struct callout sc_motoroff_ch;
224 1.28.8.2 nathanw
225 1.28.8.2 nathanw daddr_t sc_blkno; /* starting block number */
226 1.28.8.2 nathanw int sc_bcount; /* byte count left */
227 1.28.8.2 nathanw int sc_opts; /* user-set options */
228 1.28.8.2 nathanw int sc_skip; /* bytes already transferred */
229 1.28.8.2 nathanw int sc_nblks; /* #blocks currently transferring */
230 1.28.8.2 nathanw int sc_nbytes; /* #bytes currently transferring */
231 1.28.8.2 nathanw
232 1.28.8.2 nathanw int sc_drive; /* physical unit number */
233 1.28.8.2 nathanw int sc_flags;
234 1.28.8.2 nathanw #define FD_OPEN 0x01 /* it's open */
235 1.28.8.2 nathanw #define FD_MOTOR 0x02 /* motor should be on */
236 1.28.8.2 nathanw #define FD_MOTOR_WAIT 0x04 /* motor coming up */
237 1.28.8.2 nathanw #define FD_HAVELAB 0x08 /* got a disklabel */
238 1.28.8.2 nathanw int sc_cylin; /* where we think the head is */
239 1.28.8.2 nathanw
240 1.28.8.2 nathanw void *sc_sdhook; /* saved shutdown hook for drive. */
241 1.28.8.2 nathanw
242 1.28.8.2 nathanw TAILQ_ENTRY(fd_softc) sc_drivechain;
243 1.28.8.2 nathanw int sc_ops; /* I/O ops since last switch */
244 1.28.8.3 nathanw struct bufq_state sc_q; /* pending I/O requests */
245 1.28.8.2 nathanw int sc_active; /* number of active I/O operations */
246 1.28.8.2 nathanw };
247 1.28.8.2 nathanw
248 1.28.8.2 nathanw /* floppy driver configuration */
249 1.28.8.2 nathanw int fdprobe __P((struct device *, struct cfdata *, void *));
250 1.28.8.2 nathanw void fdattach __P((struct device *, struct device *, void *));
251 1.28.8.2 nathanw
252 1.28.8.2 nathanw struct cfattach hdfd_ca = {
253 1.28.8.2 nathanw sizeof(struct fd_softc), fdprobe, fdattach
254 1.28.8.2 nathanw };
255 1.28.8.2 nathanw
256 1.28.8.2 nathanw extern struct cfdriver hdfd_cd;
257 1.28.8.2 nathanw
258 1.28.8.2 nathanw void fdstrategy __P((struct buf *));
259 1.28.8.2 nathanw void fdstart __P((struct fd_softc *));
260 1.28.8.2 nathanw
261 1.28.8.2 nathanw struct dkdriver fddkdriver = { fdstrategy };
262 1.28.8.2 nathanw
263 1.28.8.2 nathanw void fd_set_motor __P((struct fdc_softc *fdc, int reset));
264 1.28.8.2 nathanw void fd_motor_off __P((void *arg));
265 1.28.8.2 nathanw void fd_motor_on __P((void *arg));
266 1.28.8.2 nathanw int fdcresult __P((struct fdc_softc *fdc));
267 1.28.8.2 nathanw int out_fdc __P((u_char x));
268 1.28.8.2 nathanw void fdc_ctrl_intr __P((struct clockframe));
269 1.28.8.2 nathanw void fdcstart __P((struct fdc_softc *fdc));
270 1.28.8.2 nathanw void fdcstatus __P((struct device *dv, int n, char *s));
271 1.28.8.2 nathanw void fdctimeout __P((void *arg));
272 1.28.8.2 nathanw void fdcpseudointr __P((void *arg));
273 1.28.8.2 nathanw int fdcintr __P((void *));
274 1.28.8.2 nathanw void fdcretry __P((struct fdc_softc *fdc));
275 1.28.8.2 nathanw void fdfinish __P((struct fd_softc *fd, struct buf *bp));
276 1.28.8.2 nathanw int fdformat __P((dev_t, struct ne7_fd_formb *, struct proc *));
277 1.28.8.2 nathanw
278 1.28.8.2 nathanw static void fdgetdisklabel __P((struct fd_softc *, dev_t));
279 1.28.8.2 nathanw static void fdgetdefaultlabel __P((struct fd_softc *, struct disklabel *,
280 1.28.8.2 nathanw int));
281 1.28.8.2 nathanw
282 1.28.8.2 nathanw __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
283 1.28.8.2 nathanw
284 1.28.8.2 nathanw int
285 1.28.8.2 nathanw fdcprobe(parent, cfp, aux)
286 1.28.8.2 nathanw struct device *parent;
287 1.28.8.2 nathanw struct cfdata *cfp;
288 1.28.8.2 nathanw void *aux;
289 1.28.8.2 nathanw {
290 1.28.8.2 nathanw static int fdc_matched = 0;
291 1.28.8.2 nathanw bus_space_tag_t mb_tag;
292 1.28.8.2 nathanw
293 1.28.8.2 nathanw /* Match only once */
294 1.28.8.2 nathanw if(strcmp("fdc", aux) || fdc_matched)
295 1.28.8.2 nathanw return(0);
296 1.28.8.2 nathanw
297 1.28.8.2 nathanw if (!atari_realconfig)
298 1.28.8.2 nathanw return 0;
299 1.28.8.2 nathanw
300 1.28.8.2 nathanw if ((mb_tag = mb_alloc_bus_space_tag()) == NULL)
301 1.28.8.2 nathanw return 0;
302 1.28.8.2 nathanw
303 1.28.8.2 nathanw if (bus_space_map(mb_tag, FD_IOBASE, FD_IOSIZE, 0,
304 1.28.8.2 nathanw (caddr_t*)&fdio_addr)) {
305 1.28.8.2 nathanw printf("fdcprobe: cannot map io-area\n");
306 1.28.8.2 nathanw mb_free_bus_space_tag(mb_tag);
307 1.28.8.2 nathanw return (0);
308 1.28.8.2 nathanw }
309 1.28.8.2 nathanw
310 1.28.8.2 nathanw #ifdef FD_DEBUG
311 1.28.8.2 nathanw printf("fdcprobe: I/O mapping done va: %p\n", fdio_addr);
312 1.28.8.2 nathanw #endif
313 1.28.8.2 nathanw
314 1.28.8.2 nathanw /* reset */
315 1.28.8.2 nathanw wrt_fdc_reg(fdout, 0);
316 1.28.8.2 nathanw delay(100);
317 1.28.8.2 nathanw wrt_fdc_reg(fdout, FDO_FRST);
318 1.28.8.2 nathanw
319 1.28.8.2 nathanw /* see if it can handle a command */
320 1.28.8.2 nathanw if (out_fdc(NE7CMD_SPECIFY) < 0)
321 1.28.8.2 nathanw goto out;
322 1.28.8.2 nathanw out_fdc(0xdf);
323 1.28.8.2 nathanw out_fdc(7);
324 1.28.8.2 nathanw
325 1.28.8.2 nathanw fdc_matched = 1;
326 1.28.8.2 nathanw
327 1.28.8.2 nathanw out:
328 1.28.8.2 nathanw if (fdc_matched == 0) {
329 1.28.8.2 nathanw bus_space_unmap(mb_tag, (caddr_t)fdio_addr, FD_IOSIZE);
330 1.28.8.2 nathanw mb_free_bus_space_tag(mb_tag);
331 1.28.8.2 nathanw }
332 1.28.8.2 nathanw
333 1.28.8.2 nathanw return fdc_matched;
334 1.28.8.2 nathanw }
335 1.28.8.2 nathanw
336 1.28.8.2 nathanw /*
337 1.28.8.2 nathanw * Arguments passed between fdcattach and fdprobe.
338 1.28.8.2 nathanw */
339 1.28.8.2 nathanw struct fdc_attach_args {
340 1.28.8.2 nathanw int fa_drive;
341 1.28.8.2 nathanw struct fd_type *fa_deftype;
342 1.28.8.2 nathanw };
343 1.28.8.2 nathanw
344 1.28.8.2 nathanw /*
345 1.28.8.2 nathanw * Print the location of a disk drive (called just before attaching the
346 1.28.8.2 nathanw * the drive). If `fdc' is not NULL, the drive was found but was not
347 1.28.8.2 nathanw * in the system config file; print the drive name as well.
348 1.28.8.2 nathanw * Return QUIET (config_find ignores this if the device was configured) to
349 1.28.8.2 nathanw * avoid printing `fdN not configured' messages.
350 1.28.8.2 nathanw */
351 1.28.8.2 nathanw int
352 1.28.8.2 nathanw fdprint(aux, fdc)
353 1.28.8.2 nathanw void *aux;
354 1.28.8.2 nathanw const char *fdc;
355 1.28.8.2 nathanw {
356 1.28.8.2 nathanw register struct fdc_attach_args *fa = aux;
357 1.28.8.2 nathanw
358 1.28.8.2 nathanw if (!fdc)
359 1.28.8.2 nathanw printf(" drive %d", fa->fa_drive);
360 1.28.8.2 nathanw return QUIET;
361 1.28.8.2 nathanw }
362 1.28.8.2 nathanw
363 1.28.8.2 nathanw void
364 1.28.8.2 nathanw fdcattach(parent, self, aux)
365 1.28.8.2 nathanw struct device *parent, *self;
366 1.28.8.2 nathanw void *aux;
367 1.28.8.2 nathanw {
368 1.28.8.2 nathanw struct fdc_softc *fdc = (void *)self;
369 1.28.8.2 nathanw struct fdc_attach_args fa;
370 1.28.8.2 nathanw int has_fifo;
371 1.28.8.2 nathanw
372 1.28.8.2 nathanw has_fifo = 0;
373 1.28.8.2 nathanw
374 1.28.8.2 nathanw fdc->sc_state = DEVIDLE;
375 1.28.8.2 nathanw TAILQ_INIT(&fdc->sc_drives);
376 1.28.8.2 nathanw
377 1.28.8.2 nathanw out_fdc(NE7CMD_CONFIGURE);
378 1.28.8.2 nathanw if (out_fdc(0) == 0) {
379 1.28.8.2 nathanw out_fdc(0x1a); /* No polling, fifo depth = 10 */
380 1.28.8.2 nathanw out_fdc(0);
381 1.28.8.2 nathanw
382 1.28.8.2 nathanw /* Retain configuration across resets */
383 1.28.8.2 nathanw out_fdc(NE7CMD_LOCK);
384 1.28.8.2 nathanw (void)fdcresult(fdc);
385 1.28.8.2 nathanw has_fifo = 1;
386 1.28.8.2 nathanw }
387 1.28.8.2 nathanw else {
388 1.28.8.2 nathanw (void)rd_fdc_reg(fddata);
389 1.28.8.2 nathanw printf(": no fifo");
390 1.28.8.2 nathanw }
391 1.28.8.2 nathanw
392 1.28.8.2 nathanw printf("\n");
393 1.28.8.2 nathanw
394 1.28.8.2 nathanw callout_init(&fdc->sc_timo_ch);
395 1.28.8.2 nathanw callout_init(&fdc->sc_intr_ch);
396 1.28.8.2 nathanw
397 1.28.8.2 nathanw if (intr_establish(22, USER_VEC|FAST_VEC, 0,
398 1.28.8.2 nathanw (hw_ifun_t)(has_fifo ? mfp_hdfd_fifo : mfp_hdfd_nf),
399 1.28.8.2 nathanw NULL) == NULL) {
400 1.28.8.2 nathanw printf("fdcattach: Can't establish interrupt\n");
401 1.28.8.2 nathanw return;
402 1.28.8.2 nathanw }
403 1.28.8.2 nathanw
404 1.28.8.2 nathanw /*
405 1.28.8.2 nathanw * Setup the interrupt logic.
406 1.28.8.2 nathanw */
407 1.28.8.2 nathanw MFP2->mf_iprb = (u_int8_t)~IB_DCHG;
408 1.28.8.2 nathanw MFP2->mf_imrb |= IB_DCHG;
409 1.28.8.2 nathanw MFP2->mf_aer |= 0x10; /* fdc int low->high */
410 1.28.8.2 nathanw
411 1.28.8.2 nathanw /* physical limit: four drives per controller. */
412 1.28.8.2 nathanw for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
413 1.28.8.2 nathanw /*
414 1.28.8.2 nathanw * XXX: Choose something sensible as a default...
415 1.28.8.2 nathanw */
416 1.28.8.2 nathanw fa.fa_deftype = &fd_types[2]; /* 1.44MB */
417 1.28.8.2 nathanw (void)config_found(self, (void *)&fa, fdprint);
418 1.28.8.2 nathanw }
419 1.28.8.2 nathanw }
420 1.28.8.2 nathanw
421 1.28.8.2 nathanw int
422 1.28.8.2 nathanw fdprobe(parent, cfp, aux)
423 1.28.8.2 nathanw struct device *parent;
424 1.28.8.2 nathanw struct cfdata *cfp;
425 1.28.8.2 nathanw void *aux;
426 1.28.8.2 nathanw {
427 1.28.8.2 nathanw struct fdc_softc *fdc = (void *)parent;
428 1.28.8.2 nathanw struct fdc_attach_args *fa = aux;
429 1.28.8.2 nathanw int drive = fa->fa_drive;
430 1.28.8.2 nathanw int n;
431 1.28.8.2 nathanw
432 1.28.8.2 nathanw if (cfp->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
433 1.28.8.2 nathanw cfp->cf_loc[FDCCF_UNIT] != drive)
434 1.28.8.2 nathanw return 0;
435 1.28.8.2 nathanw /*
436 1.28.8.2 nathanw * XXX
437 1.28.8.2 nathanw * This is to work around some odd interactions between this driver
438 1.28.8.2 nathanw * and SMC Ethernet cards.
439 1.28.8.2 nathanw */
440 1.28.8.2 nathanw if (cfp->cf_loc[FDCCF_UNIT] == FDCCF_UNIT_DEFAULT && drive >= 2)
441 1.28.8.2 nathanw return 0;
442 1.28.8.2 nathanw
443 1.28.8.2 nathanw /* select drive and turn on motor */
444 1.28.8.2 nathanw wrt_fdc_reg(fdout, drive | FDO_FRST | FDO_MOEN(drive));
445 1.28.8.2 nathanw
446 1.28.8.2 nathanw /* wait for motor to spin up */
447 1.28.8.2 nathanw delay(250000);
448 1.28.8.2 nathanw out_fdc(NE7CMD_RECAL);
449 1.28.8.2 nathanw out_fdc(drive);
450 1.28.8.2 nathanw
451 1.28.8.2 nathanw /* wait for recalibrate */
452 1.28.8.2 nathanw delay(2000000);
453 1.28.8.2 nathanw out_fdc(NE7CMD_SENSEI);
454 1.28.8.2 nathanw n = fdcresult(fdc);
455 1.28.8.2 nathanw
456 1.28.8.2 nathanw #ifdef FD_DEBUG
457 1.28.8.2 nathanw {
458 1.28.8.2 nathanw int i;
459 1.28.8.2 nathanw printf("fdprobe: status");
460 1.28.8.2 nathanw for (i = 0; i < n; i++)
461 1.28.8.2 nathanw printf(" %x", fdc->sc_status[i]);
462 1.28.8.2 nathanw printf("\n");
463 1.28.8.2 nathanw }
464 1.28.8.2 nathanw #endif
465 1.28.8.2 nathanw intr_arg = (void*)fdc;
466 1.28.8.2 nathanw if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
467 1.28.8.2 nathanw return 0;
468 1.28.8.2 nathanw /* turn off motor */
469 1.28.8.2 nathanw wrt_fdc_reg(fdout, FDO_FRST);
470 1.28.8.2 nathanw
471 1.28.8.2 nathanw return 1;
472 1.28.8.2 nathanw }
473 1.28.8.2 nathanw
474 1.28.8.2 nathanw /*
475 1.28.8.2 nathanw * Controller is working, and drive responded. Attach it.
476 1.28.8.2 nathanw */
477 1.28.8.2 nathanw void
478 1.28.8.2 nathanw fdattach(parent, self, aux)
479 1.28.8.2 nathanw struct device *parent, *self;
480 1.28.8.2 nathanw void *aux;
481 1.28.8.2 nathanw {
482 1.28.8.2 nathanw struct fdc_softc *fdc = (void *)parent;
483 1.28.8.2 nathanw struct fd_softc *fd = (void *)self;
484 1.28.8.2 nathanw struct fdc_attach_args *fa = aux;
485 1.28.8.2 nathanw struct fd_type *type = fa->fa_deftype;
486 1.28.8.2 nathanw int drive = fa->fa_drive;
487 1.28.8.2 nathanw
488 1.28.8.2 nathanw callout_init(&fd->sc_motoron_ch);
489 1.28.8.2 nathanw callout_init(&fd->sc_motoroff_ch);
490 1.28.8.2 nathanw
491 1.28.8.2 nathanw /* XXX Allow `flags' to override device type? */
492 1.28.8.2 nathanw
493 1.28.8.2 nathanw if (type)
494 1.28.8.2 nathanw printf(": %s %d cyl, %d head, %d sec\n", type->name,
495 1.28.8.2 nathanw type->tracks, type->heads, type->sectrac);
496 1.28.8.2 nathanw else
497 1.28.8.2 nathanw printf(": density unknown\n");
498 1.28.8.2 nathanw
499 1.28.8.3 nathanw bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
500 1.28.8.2 nathanw fd->sc_cylin = -1;
501 1.28.8.2 nathanw fd->sc_drive = drive;
502 1.28.8.2 nathanw fd->sc_deftype = type;
503 1.28.8.2 nathanw fdc->sc_fd[drive] = fd;
504 1.28.8.2 nathanw
505 1.28.8.2 nathanw /*
506 1.28.8.2 nathanw * Initialize and attach the disk structure.
507 1.28.8.2 nathanw */
508 1.28.8.2 nathanw fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
509 1.28.8.2 nathanw fd->sc_dk.dk_driver = &fddkdriver;
510 1.28.8.2 nathanw disk_attach(&fd->sc_dk);
511 1.28.8.2 nathanw
512 1.28.8.2 nathanw /* Needed to power off if the motor is on when we halt. */
513 1.28.8.2 nathanw fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
514 1.28.8.2 nathanw }
515 1.28.8.2 nathanw
516 1.28.8.2 nathanw /*
517 1.28.8.2 nathanw * This is called from the assembly part of the interrupt handler
518 1.28.8.2 nathanw * when it is clear that the interrupt was not related to shoving
519 1.28.8.2 nathanw * data.
520 1.28.8.2 nathanw */
521 1.28.8.2 nathanw void
522 1.28.8.2 nathanw fdc_ctrl_intr(frame)
523 1.28.8.2 nathanw struct clockframe frame;
524 1.28.8.2 nathanw {
525 1.28.8.2 nathanw int s;
526 1.28.8.2 nathanw
527 1.28.8.2 nathanw /*
528 1.28.8.2 nathanw * Disable further interrupts. The fdcintr() routine
529 1.28.8.2 nathanw * explicitly enables them when needed.
530 1.28.8.2 nathanw */
531 1.28.8.2 nathanw MFP2->mf_ierb &= ~IB_DCHG;
532 1.28.8.2 nathanw
533 1.28.8.2 nathanw /*
534 1.28.8.2 nathanw * Set fddmalen to zero so no pseudo-dma transfers will
535 1.28.8.2 nathanw * occur.
536 1.28.8.2 nathanw */
537 1.28.8.2 nathanw fddmalen = 0;
538 1.28.8.2 nathanw
539 1.28.8.2 nathanw if (!BASEPRI(frame.cf_sr)) {
540 1.28.8.2 nathanw /*
541 1.28.8.2 nathanw * We don't want to stay on ipl6.....
542 1.28.8.2 nathanw */
543 1.28.8.2 nathanw add_sicallback((si_farg)fdcpseudointr, intr_arg, 0);
544 1.28.8.2 nathanw }
545 1.28.8.2 nathanw else {
546 1.28.8.2 nathanw s = splbio();
547 1.28.8.2 nathanw (void) fdcintr(intr_arg);
548 1.28.8.2 nathanw splx(s);
549 1.28.8.2 nathanw }
550 1.28.8.2 nathanw }
551 1.28.8.2 nathanw
552 1.28.8.2 nathanw __inline struct fd_type *
553 1.28.8.2 nathanw fd_dev_to_type(fd, dev)
554 1.28.8.2 nathanw struct fd_softc *fd;
555 1.28.8.2 nathanw dev_t dev;
556 1.28.8.2 nathanw {
557 1.28.8.2 nathanw int type = FDTYPE(dev);
558 1.28.8.2 nathanw
559 1.28.8.2 nathanw if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
560 1.28.8.2 nathanw return NULL;
561 1.28.8.2 nathanw return type ? &fd_types[type - 1] : fd->sc_deftype;
562 1.28.8.2 nathanw }
563 1.28.8.2 nathanw
564 1.28.8.2 nathanw void
565 1.28.8.2 nathanw fdstrategy(bp)
566 1.28.8.2 nathanw register struct buf *bp; /* IO operation to perform */
567 1.28.8.2 nathanw {
568 1.28.8.2 nathanw struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(bp->b_dev)];
569 1.28.8.2 nathanw int sz;
570 1.28.8.2 nathanw int s;
571 1.28.8.2 nathanw
572 1.28.8.2 nathanw /* Valid unit, controller, and request? */
573 1.28.8.2 nathanw if (bp->b_blkno < 0 ||
574 1.28.8.2 nathanw ((bp->b_bcount % FDC_BSIZE) != 0 &&
575 1.28.8.2 nathanw (bp->b_flags & B_FORMAT) == 0)) {
576 1.28.8.2 nathanw bp->b_error = EINVAL;
577 1.28.8.2 nathanw goto bad;
578 1.28.8.2 nathanw }
579 1.28.8.2 nathanw
580 1.28.8.2 nathanw /* If it's a null transfer, return immediately. */
581 1.28.8.2 nathanw if (bp->b_bcount == 0)
582 1.28.8.2 nathanw goto done;
583 1.28.8.2 nathanw
584 1.28.8.2 nathanw sz = howmany(bp->b_bcount, FDC_BSIZE);
585 1.28.8.2 nathanw
586 1.28.8.2 nathanw if (bp->b_blkno + sz > fd->sc_type->size) {
587 1.28.8.2 nathanw sz = fd->sc_type->size - bp->b_blkno;
588 1.28.8.2 nathanw if (sz == 0) {
589 1.28.8.2 nathanw /* If exactly at end of disk, return EOF. */
590 1.28.8.2 nathanw goto done;
591 1.28.8.2 nathanw }
592 1.28.8.2 nathanw if (sz < 0) {
593 1.28.8.2 nathanw /* If past end of disk, return EINVAL. */
594 1.28.8.2 nathanw bp->b_error = EINVAL;
595 1.28.8.2 nathanw goto bad;
596 1.28.8.2 nathanw }
597 1.28.8.2 nathanw /* Otherwise, truncate request. */
598 1.28.8.2 nathanw bp->b_bcount = sz << DEV_BSHIFT;
599 1.28.8.2 nathanw }
600 1.28.8.2 nathanw
601 1.28.8.2 nathanw bp->b_rawblkno = bp->b_blkno;
602 1.28.8.2 nathanw bp->b_cylinder = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl;
603 1.28.8.2 nathanw
604 1.28.8.2 nathanw #ifdef FD_DEBUG
605 1.28.8.2 nathanw printf("fdstrategy: b_blkno %d b_bcount %ld blkno %ld cylin %ld sz"
606 1.28.8.2 nathanw " %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno,
607 1.28.8.2 nathanw bp->b_cylinder, sz);
608 1.28.8.2 nathanw #endif
609 1.28.8.2 nathanw
610 1.28.8.2 nathanw /* Queue transfer on drive, activate drive and controller if idle. */
611 1.28.8.2 nathanw s = splbio();
612 1.28.8.3 nathanw BUFQ_PUT(&fd->sc_q, bp);
613 1.28.8.2 nathanw callout_stop(&fd->sc_motoroff_ch); /* a good idea */
614 1.28.8.2 nathanw if (fd->sc_active == 0)
615 1.28.8.2 nathanw fdstart(fd);
616 1.28.8.2 nathanw #ifdef DIAGNOSTIC
617 1.28.8.2 nathanw else {
618 1.28.8.2 nathanw struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
619 1.28.8.2 nathanw if (fdc->sc_state == DEVIDLE) {
620 1.28.8.2 nathanw printf("fdstrategy: controller inactive\n");
621 1.28.8.2 nathanw fdcstart(fdc);
622 1.28.8.2 nathanw }
623 1.28.8.2 nathanw }
624 1.28.8.2 nathanw #endif
625 1.28.8.2 nathanw splx(s);
626 1.28.8.2 nathanw return;
627 1.28.8.2 nathanw
628 1.28.8.2 nathanw bad:
629 1.28.8.2 nathanw bp->b_flags |= B_ERROR;
630 1.28.8.2 nathanw done:
631 1.28.8.2 nathanw /* Toss transfer; we're done early. */
632 1.28.8.2 nathanw bp->b_resid = bp->b_bcount;
633 1.28.8.2 nathanw biodone(bp);
634 1.28.8.2 nathanw }
635 1.28.8.2 nathanw
636 1.28.8.2 nathanw void
637 1.28.8.2 nathanw fdstart(fd)
638 1.28.8.2 nathanw struct fd_softc *fd;
639 1.28.8.2 nathanw {
640 1.28.8.2 nathanw struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
641 1.28.8.2 nathanw int active = fdc->sc_drives.tqh_first != 0;
642 1.28.8.2 nathanw
643 1.28.8.2 nathanw /* Link into controller queue. */
644 1.28.8.2 nathanw fd->sc_active = 1;
645 1.28.8.2 nathanw TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
646 1.28.8.2 nathanw
647 1.28.8.2 nathanw /* If controller not already active, start it. */
648 1.28.8.2 nathanw if (!active)
649 1.28.8.2 nathanw fdcstart(fdc);
650 1.28.8.2 nathanw }
651 1.28.8.2 nathanw
652 1.28.8.2 nathanw void
653 1.28.8.2 nathanw fdfinish(fd, bp)
654 1.28.8.2 nathanw struct fd_softc *fd;
655 1.28.8.2 nathanw struct buf *bp;
656 1.28.8.2 nathanw {
657 1.28.8.2 nathanw struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
658 1.28.8.2 nathanw
659 1.28.8.2 nathanw /*
660 1.28.8.2 nathanw * Move this drive to the end of the queue to give others a `fair'
661 1.28.8.2 nathanw * chance. We only force a switch if N operations are completed while
662 1.28.8.2 nathanw * another drive is waiting to be serviced, since there is a long motor
663 1.28.8.2 nathanw * startup delay whenever we switch.
664 1.28.8.2 nathanw */
665 1.28.8.3 nathanw (void)BUFQ_GET(&fd->sc_q);
666 1.28.8.2 nathanw if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
667 1.28.8.2 nathanw fd->sc_ops = 0;
668 1.28.8.2 nathanw TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
669 1.28.8.3 nathanw if (BUFQ_PEEK(&fd->sc_q) != NULL)
670 1.28.8.2 nathanw TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
671 1.28.8.2 nathanw else
672 1.28.8.2 nathanw fd->sc_active = 0;
673 1.28.8.2 nathanw }
674 1.28.8.2 nathanw bp->b_resid = fd->sc_bcount;
675 1.28.8.2 nathanw fd->sc_skip = 0;
676 1.28.8.2 nathanw
677 1.28.8.2 nathanw biodone(bp);
678 1.28.8.2 nathanw /* turn off motor 5s from now */
679 1.28.8.2 nathanw callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
680 1.28.8.2 nathanw fdc->sc_state = DEVIDLE;
681 1.28.8.2 nathanw }
682 1.28.8.2 nathanw
683 1.28.8.2 nathanw int
684 1.28.8.2 nathanw fdread(dev, uio, flags)
685 1.28.8.2 nathanw dev_t dev;
686 1.28.8.2 nathanw struct uio *uio;
687 1.28.8.2 nathanw int flags;
688 1.28.8.2 nathanw {
689 1.28.8.2 nathanw return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
690 1.28.8.2 nathanw }
691 1.28.8.2 nathanw
692 1.28.8.2 nathanw int
693 1.28.8.2 nathanw fdwrite(dev, uio, flags)
694 1.28.8.2 nathanw dev_t dev;
695 1.28.8.2 nathanw struct uio *uio;
696 1.28.8.2 nathanw int flags;
697 1.28.8.2 nathanw {
698 1.28.8.2 nathanw return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
699 1.28.8.2 nathanw }
700 1.28.8.2 nathanw
701 1.28.8.2 nathanw void
702 1.28.8.2 nathanw fd_set_motor(fdc, reset)
703 1.28.8.2 nathanw struct fdc_softc *fdc;
704 1.28.8.2 nathanw int reset;
705 1.28.8.2 nathanw {
706 1.28.8.2 nathanw struct fd_softc *fd;
707 1.28.8.2 nathanw u_char status;
708 1.28.8.2 nathanw int n;
709 1.28.8.2 nathanw
710 1.28.8.2 nathanw if ((fd = fdc->sc_drives.tqh_first) != NULL)
711 1.28.8.2 nathanw status = fd->sc_drive;
712 1.28.8.2 nathanw else
713 1.28.8.2 nathanw status = 0;
714 1.28.8.2 nathanw if (!reset)
715 1.28.8.2 nathanw status |= FDO_FRST | FDO_FDMAEN;
716 1.28.8.2 nathanw for (n = 0; n < 4; n++)
717 1.28.8.2 nathanw if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
718 1.28.8.2 nathanw status |= FDO_MOEN(n);
719 1.28.8.2 nathanw wrt_fdc_reg(fdout, status);
720 1.28.8.2 nathanw }
721 1.28.8.2 nathanw
722 1.28.8.2 nathanw void
723 1.28.8.2 nathanw fd_motor_off(arg)
724 1.28.8.2 nathanw void *arg;
725 1.28.8.2 nathanw {
726 1.28.8.2 nathanw struct fd_softc *fd = arg;
727 1.28.8.2 nathanw int s;
728 1.28.8.2 nathanw
729 1.28.8.2 nathanw s = splbio();
730 1.28.8.2 nathanw fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
731 1.28.8.2 nathanw fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
732 1.28.8.2 nathanw splx(s);
733 1.28.8.2 nathanw }
734 1.28.8.2 nathanw
735 1.28.8.2 nathanw void
736 1.28.8.2 nathanw fd_motor_on(arg)
737 1.28.8.2 nathanw void *arg;
738 1.28.8.2 nathanw {
739 1.28.8.2 nathanw struct fd_softc *fd = arg;
740 1.28.8.2 nathanw struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
741 1.28.8.2 nathanw int s;
742 1.28.8.2 nathanw
743 1.28.8.2 nathanw s = splbio();
744 1.28.8.2 nathanw fd->sc_flags &= ~FD_MOTOR_WAIT;
745 1.28.8.2 nathanw if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
746 1.28.8.2 nathanw (void) fdcintr(fdc);
747 1.28.8.2 nathanw splx(s);
748 1.28.8.2 nathanw }
749 1.28.8.2 nathanw
750 1.28.8.2 nathanw int
751 1.28.8.2 nathanw fdcresult(fdc)
752 1.28.8.2 nathanw struct fdc_softc *fdc;
753 1.28.8.2 nathanw {
754 1.28.8.2 nathanw u_char i;
755 1.28.8.2 nathanw int j = 100000,
756 1.28.8.2 nathanw n = 0;
757 1.28.8.2 nathanw
758 1.28.8.2 nathanw for (; j; j--) {
759 1.28.8.2 nathanw i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB);
760 1.28.8.2 nathanw if (i == NE7_RQM)
761 1.28.8.2 nathanw return n;
762 1.28.8.2 nathanw if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
763 1.28.8.2 nathanw if (n >= sizeof(fdc->sc_status)) {
764 1.28.8.2 nathanw log(LOG_ERR, "fdcresult: overrun\n");
765 1.28.8.2 nathanw return -1;
766 1.28.8.2 nathanw }
767 1.28.8.2 nathanw fdc->sc_status[n++] = rd_fdc_reg(fddata);
768 1.28.8.2 nathanw }
769 1.28.8.2 nathanw else delay(10);
770 1.28.8.2 nathanw }
771 1.28.8.2 nathanw log(LOG_ERR, "fdcresult: timeout\n");
772 1.28.8.2 nathanw return -1;
773 1.28.8.2 nathanw }
774 1.28.8.2 nathanw
775 1.28.8.2 nathanw int
776 1.28.8.2 nathanw out_fdc(x)
777 1.28.8.2 nathanw u_char x;
778 1.28.8.2 nathanw {
779 1.28.8.2 nathanw int i = 100000;
780 1.28.8.2 nathanw
781 1.28.8.2 nathanw while (((rd_fdc_reg(fdsts) & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0)
782 1.28.8.2 nathanw delay(1);
783 1.28.8.2 nathanw if (i <= 0)
784 1.28.8.2 nathanw return -1;
785 1.28.8.2 nathanw wrt_fdc_reg(fddata, x);
786 1.28.8.2 nathanw return 0;
787 1.28.8.2 nathanw }
788 1.28.8.2 nathanw
789 1.28.8.2 nathanw int
790 1.28.8.2 nathanw fdopen(dev, flags, mode, p)
791 1.28.8.2 nathanw dev_t dev;
792 1.28.8.2 nathanw int flags;
793 1.28.8.2 nathanw int mode;
794 1.28.8.2 nathanw struct proc *p;
795 1.28.8.2 nathanw {
796 1.28.8.2 nathanw int unit;
797 1.28.8.2 nathanw struct fd_softc *fd;
798 1.28.8.2 nathanw struct fd_type *type;
799 1.28.8.2 nathanw
800 1.28.8.2 nathanw unit = FDUNIT(dev);
801 1.28.8.2 nathanw if (unit >= hdfd_cd.cd_ndevs)
802 1.28.8.2 nathanw return ENXIO;
803 1.28.8.2 nathanw fd = hdfd_cd.cd_devs[unit];
804 1.28.8.2 nathanw if (fd == 0)
805 1.28.8.2 nathanw return ENXIO;
806 1.28.8.2 nathanw type = fd_dev_to_type(fd, dev);
807 1.28.8.2 nathanw if (type == NULL)
808 1.28.8.2 nathanw return ENXIO;
809 1.28.8.2 nathanw
810 1.28.8.2 nathanw if ((fd->sc_flags & FD_OPEN) != 0 &&
811 1.28.8.2 nathanw fd->sc_type != type)
812 1.28.8.2 nathanw return EBUSY;
813 1.28.8.2 nathanw
814 1.28.8.2 nathanw fd->sc_type = type;
815 1.28.8.2 nathanw fd->sc_cylin = -1;
816 1.28.8.2 nathanw fd->sc_flags |= FD_OPEN;
817 1.28.8.2 nathanw fdgetdisklabel(fd, dev);
818 1.28.8.2 nathanw
819 1.28.8.2 nathanw return 0;
820 1.28.8.2 nathanw }
821 1.28.8.2 nathanw
822 1.28.8.2 nathanw int
823 1.28.8.2 nathanw fdclose(dev, flags, mode, p)
824 1.28.8.2 nathanw dev_t dev;
825 1.28.8.2 nathanw int flags;
826 1.28.8.2 nathanw int mode;
827 1.28.8.2 nathanw struct proc *p;
828 1.28.8.2 nathanw {
829 1.28.8.2 nathanw struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
830 1.28.8.2 nathanw
831 1.28.8.2 nathanw fd->sc_flags &= ~(FD_OPEN|FD_HAVELAB);
832 1.28.8.2 nathanw fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
833 1.28.8.2 nathanw return 0;
834 1.28.8.2 nathanw }
835 1.28.8.2 nathanw
836 1.28.8.2 nathanw void
837 1.28.8.2 nathanw fdcstart(fdc)
838 1.28.8.2 nathanw struct fdc_softc *fdc;
839 1.28.8.2 nathanw {
840 1.28.8.2 nathanw
841 1.28.8.2 nathanw #ifdef DIAGNOSTIC
842 1.28.8.2 nathanw /* only got here if controller's drive queue was inactive; should
843 1.28.8.2 nathanw be in idle state */
844 1.28.8.2 nathanw if (fdc->sc_state != DEVIDLE) {
845 1.28.8.2 nathanw printf("fdcstart: not idle\n");
846 1.28.8.2 nathanw return;
847 1.28.8.2 nathanw }
848 1.28.8.2 nathanw #endif
849 1.28.8.2 nathanw (void) fdcintr(fdc);
850 1.28.8.2 nathanw }
851 1.28.8.2 nathanw
852 1.28.8.2 nathanw void
853 1.28.8.2 nathanw fdcstatus(dv, n, s)
854 1.28.8.2 nathanw struct device *dv;
855 1.28.8.2 nathanw int n;
856 1.28.8.2 nathanw char *s;
857 1.28.8.2 nathanw {
858 1.28.8.2 nathanw struct fdc_softc *fdc = (void *)dv->dv_parent;
859 1.28.8.2 nathanw char bits[64];
860 1.28.8.2 nathanw
861 1.28.8.2 nathanw if (n == 0) {
862 1.28.8.2 nathanw out_fdc(NE7CMD_SENSEI);
863 1.28.8.2 nathanw (void) fdcresult(fdc);
864 1.28.8.2 nathanw n = 2;
865 1.28.8.2 nathanw }
866 1.28.8.2 nathanw
867 1.28.8.2 nathanw printf("%s: %s", dv->dv_xname, s);
868 1.28.8.2 nathanw
869 1.28.8.2 nathanw switch (n) {
870 1.28.8.2 nathanw case 0:
871 1.28.8.2 nathanw printf("\n");
872 1.28.8.2 nathanw break;
873 1.28.8.2 nathanw case 2:
874 1.28.8.2 nathanw printf(" (st0 %s cyl %d)\n",
875 1.28.8.2 nathanw bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
876 1.28.8.2 nathanw bits, sizeof(bits)), fdc->sc_status[1]);
877 1.28.8.2 nathanw break;
878 1.28.8.2 nathanw case 7:
879 1.28.8.2 nathanw printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
880 1.28.8.2 nathanw NE7_ST0BITS, bits, sizeof(bits)));
881 1.28.8.2 nathanw printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
882 1.28.8.2 nathanw NE7_ST1BITS, bits, sizeof(bits)));
883 1.28.8.2 nathanw printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
884 1.28.8.2 nathanw NE7_ST2BITS, bits, sizeof(bits)));
885 1.28.8.2 nathanw printf(" cyl %d head %d sec %d)\n",
886 1.28.8.2 nathanw fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
887 1.28.8.2 nathanw break;
888 1.28.8.2 nathanw #ifdef DIAGNOSTIC
889 1.28.8.2 nathanw default:
890 1.28.8.2 nathanw printf("\nfdcstatus: weird size");
891 1.28.8.2 nathanw break;
892 1.28.8.2 nathanw #endif
893 1.28.8.2 nathanw }
894 1.28.8.2 nathanw }
895 1.28.8.2 nathanw
896 1.28.8.2 nathanw void
897 1.28.8.2 nathanw fdctimeout(arg)
898 1.28.8.2 nathanw void *arg;
899 1.28.8.2 nathanw {
900 1.28.8.2 nathanw struct fdc_softc *fdc = arg;
901 1.28.8.2 nathanw struct fd_softc *fd = fdc->sc_drives.tqh_first;
902 1.28.8.2 nathanw int s;
903 1.28.8.2 nathanw
904 1.28.8.2 nathanw s = splbio();
905 1.28.8.2 nathanw fdcstatus(&fd->sc_dev, 0, "timeout");
906 1.28.8.2 nathanw
907 1.28.8.3 nathanw if (BUFQ_PEEK(&fd->sc_q) != NULL)
908 1.28.8.2 nathanw fdc->sc_state++;
909 1.28.8.2 nathanw else
910 1.28.8.2 nathanw fdc->sc_state = DEVIDLE;
911 1.28.8.2 nathanw
912 1.28.8.2 nathanw (void) fdcintr(fdc);
913 1.28.8.2 nathanw splx(s);
914 1.28.8.2 nathanw }
915 1.28.8.2 nathanw
916 1.28.8.2 nathanw void
917 1.28.8.2 nathanw fdcpseudointr(arg)
918 1.28.8.2 nathanw void *arg;
919 1.28.8.2 nathanw {
920 1.28.8.2 nathanw int s;
921 1.28.8.2 nathanw
922 1.28.8.2 nathanw /* Just ensure it has the right spl. */
923 1.28.8.2 nathanw s = splbio();
924 1.28.8.2 nathanw (void) fdcintr(arg);
925 1.28.8.2 nathanw splx(s);
926 1.28.8.2 nathanw }
927 1.28.8.2 nathanw
928 1.28.8.2 nathanw int
929 1.28.8.2 nathanw fdcintr(arg)
930 1.28.8.2 nathanw void *arg;
931 1.28.8.2 nathanw {
932 1.28.8.2 nathanw struct fdc_softc *fdc = arg;
933 1.28.8.2 nathanw #define st0 fdc->sc_status[0]
934 1.28.8.2 nathanw #define st1 fdc->sc_status[1]
935 1.28.8.2 nathanw #define cyl fdc->sc_status[1]
936 1.28.8.2 nathanw
937 1.28.8.2 nathanw struct fd_softc *fd;
938 1.28.8.2 nathanw struct buf *bp;
939 1.28.8.2 nathanw int read, head, sec, i, nblks;
940 1.28.8.2 nathanw struct fd_type *type;
941 1.28.8.2 nathanw struct ne7_fd_formb *finfo = NULL;
942 1.28.8.2 nathanw
943 1.28.8.2 nathanw loop:
944 1.28.8.2 nathanw /* Is there a drive for the controller to do a transfer with? */
945 1.28.8.2 nathanw fd = fdc->sc_drives.tqh_first;
946 1.28.8.2 nathanw if (fd == NULL) {
947 1.28.8.2 nathanw fdc->sc_state = DEVIDLE;
948 1.28.8.2 nathanw return 1;
949 1.28.8.2 nathanw }
950 1.28.8.2 nathanw
951 1.28.8.2 nathanw /* Is there a transfer to this drive? If not, deactivate drive. */
952 1.28.8.3 nathanw bp = BUFQ_PEEK(&fd->sc_q);
953 1.28.8.2 nathanw if (bp == NULL) {
954 1.28.8.2 nathanw fd->sc_ops = 0;
955 1.28.8.2 nathanw TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
956 1.28.8.2 nathanw fd->sc_active = 0;
957 1.28.8.2 nathanw goto loop;
958 1.28.8.2 nathanw }
959 1.28.8.2 nathanw
960 1.28.8.2 nathanw if (bp->b_flags & B_FORMAT)
961 1.28.8.2 nathanw finfo = (struct ne7_fd_formb *)bp->b_data;
962 1.28.8.2 nathanw
963 1.28.8.2 nathanw switch (fdc->sc_state) {
964 1.28.8.2 nathanw case DEVIDLE:
965 1.28.8.2 nathanw fdc->sc_errors = 0;
966 1.28.8.2 nathanw fdc->sc_overruns = 0;
967 1.28.8.2 nathanw fd->sc_skip = 0;
968 1.28.8.2 nathanw fd->sc_bcount = bp->b_bcount;
969 1.28.8.2 nathanw fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
970 1.28.8.2 nathanw callout_stop(&fd->sc_motoroff_ch);
971 1.28.8.2 nathanw if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
972 1.28.8.2 nathanw fdc->sc_state = MOTORWAIT;
973 1.28.8.2 nathanw return 1;
974 1.28.8.2 nathanw }
975 1.28.8.2 nathanw if ((fd->sc_flags & FD_MOTOR) == 0) {
976 1.28.8.2 nathanw /* Turn on the motor, being careful about pairing. */
977 1.28.8.2 nathanw struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
978 1.28.8.2 nathanw if (ofd && ofd->sc_flags & FD_MOTOR) {
979 1.28.8.2 nathanw callout_stop(&ofd->sc_motoroff_ch);
980 1.28.8.2 nathanw ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
981 1.28.8.2 nathanw }
982 1.28.8.2 nathanw fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
983 1.28.8.2 nathanw fd_set_motor(fdc, 0);
984 1.28.8.2 nathanw fdc->sc_state = MOTORWAIT;
985 1.28.8.2 nathanw /* Allow .25s for motor to stabilize. */
986 1.28.8.2 nathanw callout_reset(&fd->sc_motoron_ch, hz / 4,
987 1.28.8.2 nathanw fd_motor_on, fd);
988 1.28.8.2 nathanw return 1;
989 1.28.8.2 nathanw }
990 1.28.8.2 nathanw /* Make sure the right drive is selected. */
991 1.28.8.2 nathanw fd_set_motor(fdc, 0);
992 1.28.8.2 nathanw
993 1.28.8.2 nathanw /* fall through */
994 1.28.8.2 nathanw case DOSEEK:
995 1.28.8.2 nathanw doseek:
996 1.28.8.2 nathanw if (fd->sc_cylin == bp->b_cylinder)
997 1.28.8.2 nathanw goto doio;
998 1.28.8.2 nathanw
999 1.28.8.2 nathanw out_fdc(NE7CMD_SPECIFY);/* specify command */
1000 1.28.8.2 nathanw out_fdc(fd->sc_type->steprate);
1001 1.28.8.2 nathanw out_fdc(0x7); /* XXX head load time == 6ms - non-dma */
1002 1.28.8.2 nathanw
1003 1.28.8.2 nathanw fdc_ienable();
1004 1.28.8.2 nathanw
1005 1.28.8.2 nathanw out_fdc(NE7CMD_SEEK); /* seek function */
1006 1.28.8.2 nathanw out_fdc(fd->sc_drive); /* drive number */
1007 1.28.8.2 nathanw out_fdc(bp->b_cylinder * fd->sc_type->step);
1008 1.28.8.2 nathanw
1009 1.28.8.2 nathanw fd->sc_cylin = -1;
1010 1.28.8.2 nathanw fdc->sc_state = SEEKWAIT;
1011 1.28.8.2 nathanw
1012 1.28.8.2 nathanw fd->sc_dk.dk_seek++;
1013 1.28.8.2 nathanw disk_busy(&fd->sc_dk);
1014 1.28.8.2 nathanw
1015 1.28.8.2 nathanw callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1016 1.28.8.2 nathanw return 1;
1017 1.28.8.2 nathanw
1018 1.28.8.2 nathanw case DOIO:
1019 1.28.8.2 nathanw doio:
1020 1.28.8.2 nathanw if (finfo)
1021 1.28.8.2 nathanw fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1022 1.28.8.2 nathanw (char *)finfo;
1023 1.28.8.2 nathanw
1024 1.28.8.2 nathanw type = fd->sc_type;
1025 1.28.8.2 nathanw sec = fd->sc_blkno % type->seccyl;
1026 1.28.8.2 nathanw head = sec / type->sectrac;
1027 1.28.8.2 nathanw sec -= head * type->sectrac;
1028 1.28.8.2 nathanw nblks = type->sectrac - sec;
1029 1.28.8.2 nathanw nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1030 1.28.8.2 nathanw nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1031 1.28.8.2 nathanw fd->sc_nblks = nblks;
1032 1.28.8.2 nathanw fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
1033 1.28.8.2 nathanw #ifdef DIAGNOSTIC
1034 1.28.8.2 nathanw {
1035 1.28.8.2 nathanw int block;
1036 1.28.8.2 nathanw
1037 1.28.8.2 nathanw block = (fd->sc_cylin * type->heads + head)
1038 1.28.8.2 nathanw * type->sectrac + sec;
1039 1.28.8.2 nathanw if (block != fd->sc_blkno) {
1040 1.28.8.2 nathanw printf("fdcintr: block %d != blkno %d\n",
1041 1.28.8.2 nathanw block, fd->sc_blkno);
1042 1.28.8.2 nathanw #ifdef DDB
1043 1.28.8.2 nathanw Debugger();
1044 1.28.8.2 nathanw #endif
1045 1.28.8.2 nathanw }
1046 1.28.8.2 nathanw }
1047 1.28.8.2 nathanw #endif
1048 1.28.8.2 nathanw read = bp->b_flags & B_READ ? 1 : 0;
1049 1.28.8.2 nathanw
1050 1.28.8.2 nathanw /*
1051 1.28.8.2 nathanw * Setup pseudo-dma address & count
1052 1.28.8.2 nathanw */
1053 1.28.8.2 nathanw fddmaaddr = bp->b_data + fd->sc_skip;
1054 1.28.8.2 nathanw fddmalen = fd->sc_nbytes;
1055 1.28.8.2 nathanw
1056 1.28.8.2 nathanw wrt_fdc_reg(fdctl, type->rate);
1057 1.28.8.2 nathanw #ifdef FD_DEBUG
1058 1.28.8.2 nathanw printf("fdcintr: %s drive %d track %d head %d sec %d"
1059 1.28.8.2 nathanw " nblks %d\n", read ? "read" : "write",
1060 1.28.8.2 nathanw fd->sc_drive, fd->sc_cylin, head, sec, nblks);
1061 1.28.8.2 nathanw #endif
1062 1.28.8.2 nathanw fdc_ienable();
1063 1.28.8.2 nathanw
1064 1.28.8.2 nathanw if (finfo) {
1065 1.28.8.2 nathanw /* formatting */
1066 1.28.8.2 nathanw if (out_fdc(NE7CMD_FORMAT) < 0) {
1067 1.28.8.2 nathanw fdc->sc_errors = 4;
1068 1.28.8.2 nathanw fdcretry(fdc);
1069 1.28.8.2 nathanw goto loop;
1070 1.28.8.2 nathanw }
1071 1.28.8.2 nathanw out_fdc((head << 2) | fd->sc_drive);
1072 1.28.8.2 nathanw out_fdc(finfo->fd_formb_secshift);
1073 1.28.8.2 nathanw out_fdc(finfo->fd_formb_nsecs);
1074 1.28.8.2 nathanw out_fdc(finfo->fd_formb_gaplen);
1075 1.28.8.2 nathanw out_fdc(finfo->fd_formb_fillbyte);
1076 1.28.8.2 nathanw } else {
1077 1.28.8.2 nathanw if (read)
1078 1.28.8.2 nathanw out_fdc(NE7CMD_READ); /* READ */
1079 1.28.8.2 nathanw else
1080 1.28.8.2 nathanw out_fdc(NE7CMD_WRITE); /* WRITE */
1081 1.28.8.2 nathanw out_fdc((head << 2) | fd->sc_drive);
1082 1.28.8.2 nathanw out_fdc(fd->sc_cylin); /* track */
1083 1.28.8.2 nathanw out_fdc(head); /* head */
1084 1.28.8.2 nathanw out_fdc(sec + 1); /* sector +1 */
1085 1.28.8.2 nathanw out_fdc(type->secsize); /* sector size */
1086 1.28.8.2 nathanw out_fdc(sec + nblks); /* last sectors */
1087 1.28.8.2 nathanw out_fdc(type->gap1); /* gap1 size */
1088 1.28.8.2 nathanw out_fdc(type->datalen); /* data length */
1089 1.28.8.2 nathanw }
1090 1.28.8.2 nathanw fdc->sc_state = IOCOMPLETE;
1091 1.28.8.2 nathanw
1092 1.28.8.2 nathanw disk_busy(&fd->sc_dk);
1093 1.28.8.2 nathanw
1094 1.28.8.2 nathanw /* allow 2 seconds for operation */
1095 1.28.8.2 nathanw callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1096 1.28.8.2 nathanw return 1; /* will return later */
1097 1.28.8.2 nathanw
1098 1.28.8.2 nathanw case SEEKWAIT:
1099 1.28.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1100 1.28.8.2 nathanw fdc->sc_state = SEEKCOMPLETE;
1101 1.28.8.2 nathanw /* allow 1/50 second for heads to settle */
1102 1.28.8.2 nathanw callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1103 1.28.8.2 nathanw return 1;
1104 1.28.8.2 nathanw
1105 1.28.8.2 nathanw case SEEKCOMPLETE:
1106 1.28.8.2 nathanw disk_unbusy(&fd->sc_dk, 0); /* no data on seek */
1107 1.28.8.2 nathanw
1108 1.28.8.2 nathanw /* Make sure seek really happened. */
1109 1.28.8.2 nathanw out_fdc(NE7CMD_SENSEI);
1110 1.28.8.2 nathanw if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1111 1.28.8.2 nathanw cyl != bp->b_cylinder * fd->sc_type->step) {
1112 1.28.8.2 nathanw #ifdef FD_DEBUG
1113 1.28.8.2 nathanw fdcstatus(&fd->sc_dev, 2, "seek failed");
1114 1.28.8.2 nathanw #endif
1115 1.28.8.2 nathanw fdcretry(fdc);
1116 1.28.8.2 nathanw goto loop;
1117 1.28.8.2 nathanw }
1118 1.28.8.2 nathanw fd->sc_cylin = bp->b_cylinder;
1119 1.28.8.2 nathanw goto doio;
1120 1.28.8.2 nathanw
1121 1.28.8.2 nathanw case IOTIMEDOUT:
1122 1.28.8.2 nathanw case SEEKTIMEDOUT:
1123 1.28.8.2 nathanw case RECALTIMEDOUT:
1124 1.28.8.2 nathanw case RESETTIMEDOUT:
1125 1.28.8.2 nathanw fdcretry(fdc);
1126 1.28.8.2 nathanw goto loop;
1127 1.28.8.2 nathanw
1128 1.28.8.2 nathanw case IOCOMPLETE: /* IO DONE, post-analyze */
1129 1.28.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1130 1.28.8.2 nathanw
1131 1.28.8.2 nathanw disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid));
1132 1.28.8.2 nathanw
1133 1.28.8.2 nathanw if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) {
1134 1.28.8.2 nathanw /*
1135 1.28.8.2 nathanw * As the damn chip doesn't seem to have a FIFO,
1136 1.28.8.2 nathanw * accept a few overruns as a fact of life *sigh*
1137 1.28.8.2 nathanw */
1138 1.28.8.2 nathanw if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) {
1139 1.28.8.2 nathanw fdc->sc_state = DOSEEK;
1140 1.28.8.2 nathanw goto loop;
1141 1.28.8.2 nathanw }
1142 1.28.8.2 nathanw #ifdef FD_DEBUG
1143 1.28.8.2 nathanw fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1144 1.28.8.2 nathanw "read failed" : "write failed");
1145 1.28.8.2 nathanw printf("blkno %d nblks %d\n",
1146 1.28.8.2 nathanw fd->sc_blkno, fd->sc_nblks);
1147 1.28.8.2 nathanw #endif
1148 1.28.8.2 nathanw fdcretry(fdc);
1149 1.28.8.2 nathanw goto loop;
1150 1.28.8.2 nathanw }
1151 1.28.8.2 nathanw if (fdc->sc_errors) {
1152 1.28.8.2 nathanw diskerr(bp, "fd", "soft error", LOG_PRINTF,
1153 1.28.8.2 nathanw fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1154 1.28.8.2 nathanw printf("\n");
1155 1.28.8.2 nathanw fdc->sc_errors = 0;
1156 1.28.8.2 nathanw }
1157 1.28.8.2 nathanw fdc->sc_overruns = 0;
1158 1.28.8.2 nathanw fd->sc_blkno += fd->sc_nblks;
1159 1.28.8.2 nathanw fd->sc_skip += fd->sc_nbytes;
1160 1.28.8.2 nathanw fd->sc_bcount -= fd->sc_nbytes;
1161 1.28.8.2 nathanw if (!finfo && fd->sc_bcount > 0) {
1162 1.28.8.2 nathanw bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1163 1.28.8.2 nathanw goto doseek;
1164 1.28.8.2 nathanw }
1165 1.28.8.2 nathanw fdfinish(fd, bp);
1166 1.28.8.2 nathanw goto loop;
1167 1.28.8.2 nathanw
1168 1.28.8.2 nathanw case DORESET:
1169 1.28.8.2 nathanw /* try a reset, keep motor on */
1170 1.28.8.2 nathanw fd_set_motor(fdc, 1);
1171 1.28.8.2 nathanw delay(100);
1172 1.28.8.2 nathanw fd_set_motor(fdc, 0);
1173 1.28.8.2 nathanw fdc->sc_state = RESETCOMPLETE;
1174 1.28.8.2 nathanw callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1175 1.28.8.2 nathanw return 1; /* will return later */
1176 1.28.8.2 nathanw
1177 1.28.8.2 nathanw case RESETCOMPLETE:
1178 1.28.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1179 1.28.8.2 nathanw /* clear the controller output buffer */
1180 1.28.8.2 nathanw for (i = 0; i < 4; i++) {
1181 1.28.8.2 nathanw out_fdc(NE7CMD_SENSEI);
1182 1.28.8.2 nathanw (void) fdcresult(fdc);
1183 1.28.8.2 nathanw }
1184 1.28.8.2 nathanw
1185 1.28.8.2 nathanw /* fall through */
1186 1.28.8.2 nathanw case DORECAL:
1187 1.28.8.2 nathanw fdc_ienable();
1188 1.28.8.2 nathanw
1189 1.28.8.2 nathanw out_fdc(NE7CMD_RECAL); /* recalibrate function */
1190 1.28.8.2 nathanw out_fdc(fd->sc_drive);
1191 1.28.8.2 nathanw fdc->sc_state = RECALWAIT;
1192 1.28.8.2 nathanw callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1193 1.28.8.2 nathanw return 1; /* will return later */
1194 1.28.8.2 nathanw
1195 1.28.8.2 nathanw case RECALWAIT:
1196 1.28.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1197 1.28.8.2 nathanw fdc->sc_state = RECALCOMPLETE;
1198 1.28.8.2 nathanw /* allow 1/30 second for heads to settle */
1199 1.28.8.2 nathanw callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1200 1.28.8.2 nathanw return 1; /* will return later */
1201 1.28.8.2 nathanw
1202 1.28.8.2 nathanw case RECALCOMPLETE:
1203 1.28.8.2 nathanw out_fdc(NE7CMD_SENSEI);
1204 1.28.8.2 nathanw if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1205 1.28.8.2 nathanw #ifdef FD_DEBUG
1206 1.28.8.2 nathanw fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1207 1.28.8.2 nathanw #endif
1208 1.28.8.2 nathanw fdcretry(fdc);
1209 1.28.8.2 nathanw goto loop;
1210 1.28.8.2 nathanw }
1211 1.28.8.2 nathanw fd->sc_cylin = 0;
1212 1.28.8.2 nathanw goto doseek;
1213 1.28.8.2 nathanw
1214 1.28.8.2 nathanw case MOTORWAIT:
1215 1.28.8.2 nathanw if (fd->sc_flags & FD_MOTOR_WAIT)
1216 1.28.8.2 nathanw return 1; /* time's not up yet */
1217 1.28.8.2 nathanw goto doseek;
1218 1.28.8.2 nathanw
1219 1.28.8.2 nathanw default:
1220 1.28.8.2 nathanw fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1221 1.28.8.2 nathanw return 1;
1222 1.28.8.2 nathanw }
1223 1.28.8.2 nathanw #ifdef DIAGNOSTIC
1224 1.28.8.2 nathanw panic("fdcintr: impossible");
1225 1.28.8.2 nathanw #endif
1226 1.28.8.2 nathanw #undef st0
1227 1.28.8.2 nathanw #undef st1
1228 1.28.8.2 nathanw #undef cyl
1229 1.28.8.2 nathanw }
1230 1.28.8.2 nathanw
1231 1.28.8.2 nathanw void
1232 1.28.8.2 nathanw fdcretry(fdc)
1233 1.28.8.2 nathanw struct fdc_softc *fdc;
1234 1.28.8.2 nathanw {
1235 1.28.8.2 nathanw char bits[64];
1236 1.28.8.2 nathanw struct fd_softc *fd;
1237 1.28.8.2 nathanw struct buf *bp;
1238 1.28.8.2 nathanw
1239 1.28.8.2 nathanw fd = fdc->sc_drives.tqh_first;
1240 1.28.8.3 nathanw bp = BUFQ_PEEK(&fd->sc_q);
1241 1.28.8.2 nathanw
1242 1.28.8.2 nathanw if (fd->sc_opts & FDOPT_NORETRY)
1243 1.28.8.2 nathanw goto fail;
1244 1.28.8.2 nathanw
1245 1.28.8.2 nathanw switch (fdc->sc_errors) {
1246 1.28.8.2 nathanw case 0:
1247 1.28.8.2 nathanw /* try again */
1248 1.28.8.2 nathanw fdc->sc_state = DOSEEK;
1249 1.28.8.2 nathanw break;
1250 1.28.8.2 nathanw
1251 1.28.8.2 nathanw case 1: case 2: case 3:
1252 1.28.8.2 nathanw /* didn't work; try recalibrating */
1253 1.28.8.2 nathanw fdc->sc_state = DORECAL;
1254 1.28.8.2 nathanw break;
1255 1.28.8.2 nathanw
1256 1.28.8.2 nathanw case 4:
1257 1.28.8.2 nathanw /* still no go; reset the bastard */
1258 1.28.8.2 nathanw fdc->sc_state = DORESET;
1259 1.28.8.2 nathanw break;
1260 1.28.8.2 nathanw
1261 1.28.8.2 nathanw default:
1262 1.28.8.2 nathanw fail:
1263 1.28.8.2 nathanw if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1264 1.28.8.2 nathanw diskerr(bp, "fd", "hard error", LOG_PRINTF,
1265 1.28.8.2 nathanw fd->sc_skip / FDC_BSIZE,
1266 1.28.8.2 nathanw (struct disklabel *)NULL);
1267 1.28.8.2 nathanw
1268 1.28.8.2 nathanw printf(" (st0 %s",
1269 1.28.8.2 nathanw bitmask_snprintf(fdc->sc_status[0],
1270 1.28.8.2 nathanw NE7_ST0BITS, bits,
1271 1.28.8.2 nathanw sizeof(bits)));
1272 1.28.8.2 nathanw printf(" st1 %s",
1273 1.28.8.2 nathanw bitmask_snprintf(fdc->sc_status[1],
1274 1.28.8.2 nathanw NE7_ST1BITS, bits,
1275 1.28.8.2 nathanw sizeof(bits)));
1276 1.28.8.2 nathanw printf(" st2 %s",
1277 1.28.8.2 nathanw bitmask_snprintf(fdc->sc_status[2],
1278 1.28.8.2 nathanw NE7_ST2BITS, bits,
1279 1.28.8.2 nathanw sizeof(bits)));
1280 1.28.8.2 nathanw printf(" cyl %d head %d sec %d)\n",
1281 1.28.8.2 nathanw fdc->sc_status[3],
1282 1.28.8.2 nathanw fdc->sc_status[4],
1283 1.28.8.2 nathanw fdc->sc_status[5]);
1284 1.28.8.2 nathanw }
1285 1.28.8.2 nathanw bp->b_flags |= B_ERROR;
1286 1.28.8.2 nathanw bp->b_error = EIO;
1287 1.28.8.2 nathanw fdfinish(fd, bp);
1288 1.28.8.2 nathanw }
1289 1.28.8.2 nathanw fdc->sc_errors++;
1290 1.28.8.2 nathanw }
1291 1.28.8.2 nathanw
1292 1.28.8.2 nathanw int
1293 1.28.8.2 nathanw fdsize(dev)
1294 1.28.8.2 nathanw dev_t dev;
1295 1.28.8.2 nathanw {
1296 1.28.8.2 nathanw
1297 1.28.8.2 nathanw /* Swapping to floppies would not make sense. */
1298 1.28.8.2 nathanw return -1;
1299 1.28.8.2 nathanw }
1300 1.28.8.2 nathanw
1301 1.28.8.2 nathanw int
1302 1.28.8.2 nathanw fddump(dev, blkno, va, size)
1303 1.28.8.2 nathanw dev_t dev;
1304 1.28.8.2 nathanw daddr_t blkno;
1305 1.28.8.2 nathanw caddr_t va;
1306 1.28.8.2 nathanw size_t size;
1307 1.28.8.2 nathanw {
1308 1.28.8.2 nathanw
1309 1.28.8.2 nathanw /* Not implemented. */
1310 1.28.8.2 nathanw return ENXIO;
1311 1.28.8.2 nathanw }
1312 1.28.8.2 nathanw
1313 1.28.8.2 nathanw int
1314 1.28.8.2 nathanw fdioctl(dev, cmd, addr, flag, p)
1315 1.28.8.2 nathanw dev_t dev;
1316 1.28.8.2 nathanw u_long cmd;
1317 1.28.8.2 nathanw caddr_t addr;
1318 1.28.8.2 nathanw int flag;
1319 1.28.8.2 nathanw struct proc *p;
1320 1.28.8.2 nathanw {
1321 1.28.8.2 nathanw struct fd_softc *fd;
1322 1.28.8.2 nathanw struct disklabel buffer;
1323 1.28.8.2 nathanw int error;
1324 1.28.8.2 nathanw struct fdformat_parms *form_parms;
1325 1.28.8.2 nathanw struct fdformat_cmd *form_cmd;
1326 1.28.8.2 nathanw struct ne7_fd_formb *fd_formb;
1327 1.28.8.2 nathanw unsigned int scratch;
1328 1.28.8.2 nathanw int il[FD_MAX_NSEC + 1];
1329 1.28.8.2 nathanw register int i, j;
1330 1.28.8.2 nathanw
1331 1.28.8.2 nathanw fd = hdfd_cd.cd_devs[FDUNIT(dev)];
1332 1.28.8.2 nathanw
1333 1.28.8.2 nathanw switch (cmd) {
1334 1.28.8.2 nathanw case DIOCGDINFO:
1335 1.28.8.2 nathanw fdgetdisklabel(fd, dev);
1336 1.28.8.2 nathanw *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1337 1.28.8.2 nathanw return 0;
1338 1.28.8.2 nathanw
1339 1.28.8.2 nathanw case DIOCGPART:
1340 1.28.8.2 nathanw fdgetdisklabel(fd, dev);
1341 1.28.8.2 nathanw ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1342 1.28.8.2 nathanw ((struct partinfo *)addr)->part =
1343 1.28.8.2 nathanw &fd->sc_dk.dk_label->d_partitions[RAW_PART];
1344 1.28.8.2 nathanw return(0);
1345 1.28.8.2 nathanw
1346 1.28.8.2 nathanw case DIOCWLABEL:
1347 1.28.8.2 nathanw if ((flag & FWRITE) == 0)
1348 1.28.8.2 nathanw return EBADF;
1349 1.28.8.2 nathanw /* XXX do something */
1350 1.28.8.2 nathanw return 0;
1351 1.28.8.2 nathanw
1352 1.28.8.2 nathanw case DIOCSDINFO:
1353 1.28.8.2 nathanw case DIOCWDINFO:
1354 1.28.8.2 nathanw if ((flag & FWRITE) == 0)
1355 1.28.8.2 nathanw return EBADF;
1356 1.28.8.2 nathanw
1357 1.28.8.2 nathanw fd->sc_flags &= ~FD_HAVELAB; /* Invalid */
1358 1.28.8.2 nathanw error = setdisklabel(&buffer, (struct disklabel *)addr, 0,NULL);
1359 1.28.8.2 nathanw if (error)
1360 1.28.8.2 nathanw return error;
1361 1.28.8.2 nathanw
1362 1.28.8.2 nathanw if (cmd == DIOCWDINFO)
1363 1.28.8.2 nathanw error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1364 1.28.8.2 nathanw return error;
1365 1.28.8.2 nathanw
1366 1.28.8.2 nathanw case FDIOCGETFORMAT:
1367 1.28.8.2 nathanw form_parms = (struct fdformat_parms *)addr;
1368 1.28.8.2 nathanw form_parms->fdformat_version = FDFORMAT_VERSION;
1369 1.28.8.2 nathanw form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1370 1.28.8.2 nathanw form_parms->ncyl = fd->sc_type->tracks;
1371 1.28.8.2 nathanw form_parms->nspt = fd->sc_type->sectrac;
1372 1.28.8.2 nathanw form_parms->ntrk = fd->sc_type->heads;
1373 1.28.8.2 nathanw form_parms->stepspercyl = fd->sc_type->step;
1374 1.28.8.2 nathanw form_parms->gaplen = fd->sc_type->gap2;
1375 1.28.8.2 nathanw form_parms->fillbyte = fd->sc_type->fillbyte;
1376 1.28.8.2 nathanw form_parms->interleave = fd->sc_type->interleave;
1377 1.28.8.2 nathanw switch (fd->sc_type->rate) {
1378 1.28.8.2 nathanw case FDC_500KBPS:
1379 1.28.8.2 nathanw form_parms->xfer_rate = 500 * 1024;
1380 1.28.8.2 nathanw break;
1381 1.28.8.2 nathanw case FDC_300KBPS:
1382 1.28.8.2 nathanw form_parms->xfer_rate = 300 * 1024;
1383 1.28.8.2 nathanw break;
1384 1.28.8.2 nathanw case FDC_250KBPS:
1385 1.28.8.2 nathanw form_parms->xfer_rate = 250 * 1024;
1386 1.28.8.2 nathanw break;
1387 1.28.8.2 nathanw case FDC_125KBPS:
1388 1.28.8.2 nathanw form_parms->xfer_rate = 125 * 1024;
1389 1.28.8.2 nathanw break;
1390 1.28.8.2 nathanw default:
1391 1.28.8.2 nathanw return EINVAL;
1392 1.28.8.2 nathanw }
1393 1.28.8.2 nathanw return 0;
1394 1.28.8.2 nathanw
1395 1.28.8.2 nathanw case FDIOCSETFORMAT:
1396 1.28.8.2 nathanw if((flag & FWRITE) == 0)
1397 1.28.8.2 nathanw return EBADF; /* must be opened for writing */
1398 1.28.8.2 nathanw form_parms = (struct fdformat_parms *)addr;
1399 1.28.8.2 nathanw if (form_parms->fdformat_version != FDFORMAT_VERSION)
1400 1.28.8.2 nathanw return EINVAL; /* wrong version of formatting prog */
1401 1.28.8.2 nathanw
1402 1.28.8.2 nathanw scratch = form_parms->nbps >> 7;
1403 1.28.8.2 nathanw if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1404 1.28.8.2 nathanw scratch & ~(1 << (ffs(scratch)-1)))
1405 1.28.8.2 nathanw /* not a power-of-two multiple of 128 */
1406 1.28.8.2 nathanw return EINVAL;
1407 1.28.8.2 nathanw
1408 1.28.8.2 nathanw switch (form_parms->xfer_rate) {
1409 1.28.8.2 nathanw case 500 * 1024:
1410 1.28.8.2 nathanw fd->sc_type->rate = FDC_500KBPS;
1411 1.28.8.2 nathanw break;
1412 1.28.8.2 nathanw case 300 * 1024:
1413 1.28.8.2 nathanw fd->sc_type->rate = FDC_300KBPS;
1414 1.28.8.2 nathanw break;
1415 1.28.8.2 nathanw case 250 * 1024:
1416 1.28.8.2 nathanw fd->sc_type->rate = FDC_250KBPS;
1417 1.28.8.2 nathanw break;
1418 1.28.8.2 nathanw case 125 * 1024:
1419 1.28.8.2 nathanw fd->sc_type->rate = FDC_125KBPS;
1420 1.28.8.2 nathanw break;
1421 1.28.8.2 nathanw default:
1422 1.28.8.2 nathanw return EINVAL;
1423 1.28.8.2 nathanw }
1424 1.28.8.2 nathanw
1425 1.28.8.2 nathanw if (form_parms->nspt > FD_MAX_NSEC ||
1426 1.28.8.2 nathanw form_parms->fillbyte > 0xff ||
1427 1.28.8.2 nathanw form_parms->interleave > 0xff)
1428 1.28.8.2 nathanw return EINVAL;
1429 1.28.8.2 nathanw fd->sc_type->sectrac = form_parms->nspt;
1430 1.28.8.2 nathanw if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1431 1.28.8.2 nathanw return EINVAL;
1432 1.28.8.2 nathanw fd->sc_type->heads = form_parms->ntrk;
1433 1.28.8.2 nathanw fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1434 1.28.8.2 nathanw fd->sc_type->secsize = ffs(scratch)-1;
1435 1.28.8.2 nathanw fd->sc_type->gap2 = form_parms->gaplen;
1436 1.28.8.2 nathanw fd->sc_type->tracks = form_parms->ncyl;
1437 1.28.8.2 nathanw fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1438 1.28.8.2 nathanw form_parms->nbps / DEV_BSIZE;
1439 1.28.8.2 nathanw fd->sc_type->step = form_parms->stepspercyl;
1440 1.28.8.2 nathanw fd->sc_type->fillbyte = form_parms->fillbyte;
1441 1.28.8.2 nathanw fd->sc_type->interleave = form_parms->interleave;
1442 1.28.8.2 nathanw return 0;
1443 1.28.8.2 nathanw
1444 1.28.8.2 nathanw case FDIOCFORMAT_TRACK:
1445 1.28.8.2 nathanw if((flag & FWRITE) == 0)
1446 1.28.8.2 nathanw return EBADF; /* must be opened for writing */
1447 1.28.8.2 nathanw form_cmd = (struct fdformat_cmd *)addr;
1448 1.28.8.2 nathanw if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1449 1.28.8.2 nathanw return EINVAL; /* wrong version of formatting prog */
1450 1.28.8.2 nathanw
1451 1.28.8.2 nathanw if (form_cmd->head >= fd->sc_type->heads ||
1452 1.28.8.2 nathanw form_cmd->cylinder >= fd->sc_type->tracks) {
1453 1.28.8.2 nathanw return EINVAL;
1454 1.28.8.2 nathanw }
1455 1.28.8.2 nathanw
1456 1.28.8.2 nathanw fd_formb = malloc(sizeof(struct ne7_fd_formb),
1457 1.28.8.2 nathanw M_TEMP, M_NOWAIT);
1458 1.28.8.2 nathanw if (fd_formb == 0)
1459 1.28.8.2 nathanw return ENOMEM;
1460 1.28.8.2 nathanw
1461 1.28.8.2 nathanw fd_formb->head = form_cmd->head;
1462 1.28.8.2 nathanw fd_formb->cyl = form_cmd->cylinder;
1463 1.28.8.2 nathanw fd_formb->transfer_rate = fd->sc_type->rate;
1464 1.28.8.2 nathanw fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1465 1.28.8.2 nathanw fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1466 1.28.8.2 nathanw fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1467 1.28.8.2 nathanw fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1468 1.28.8.2 nathanw
1469 1.28.8.2 nathanw bzero(il,sizeof il);
1470 1.28.8.2 nathanw for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1471 1.28.8.2 nathanw while (il[(j%fd_formb->fd_formb_nsecs)+1])
1472 1.28.8.2 nathanw j++;
1473 1.28.8.2 nathanw il[(j%fd_formb->fd_formb_nsecs)+1] = i;
1474 1.28.8.2 nathanw j += fd->sc_type->interleave;
1475 1.28.8.2 nathanw }
1476 1.28.8.2 nathanw for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1477 1.28.8.2 nathanw fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1478 1.28.8.2 nathanw fd_formb->fd_formb_headno(i) = form_cmd->head;
1479 1.28.8.2 nathanw fd_formb->fd_formb_secno(i) = il[i+1];
1480 1.28.8.2 nathanw fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1481 1.28.8.2 nathanw }
1482 1.28.8.2 nathanw
1483 1.28.8.2 nathanw error = fdformat(dev, fd_formb, p);
1484 1.28.8.2 nathanw free(fd_formb, M_TEMP);
1485 1.28.8.2 nathanw return error;
1486 1.28.8.2 nathanw
1487 1.28.8.2 nathanw case FDIOCGETOPTS: /* get drive options */
1488 1.28.8.2 nathanw *(int *)addr = fd->sc_opts;
1489 1.28.8.2 nathanw return 0;
1490 1.28.8.2 nathanw
1491 1.28.8.2 nathanw case FDIOCSETOPTS: /* set drive options */
1492 1.28.8.2 nathanw fd->sc_opts = *(int *)addr;
1493 1.28.8.2 nathanw return 0;
1494 1.28.8.2 nathanw
1495 1.28.8.2 nathanw
1496 1.28.8.2 nathanw default:
1497 1.28.8.2 nathanw return ENOTTY;
1498 1.28.8.2 nathanw }
1499 1.28.8.2 nathanw
1500 1.28.8.2 nathanw #ifdef DIAGNOSTIC
1501 1.28.8.2 nathanw panic("fdioctl: impossible");
1502 1.28.8.2 nathanw #endif
1503 1.28.8.2 nathanw }
1504 1.28.8.2 nathanw
1505 1.28.8.2 nathanw int
1506 1.28.8.2 nathanw fdformat(dev, finfo, p)
1507 1.28.8.2 nathanw dev_t dev;
1508 1.28.8.2 nathanw struct ne7_fd_formb *finfo;
1509 1.28.8.2 nathanw struct proc *p;
1510 1.28.8.2 nathanw {
1511 1.28.8.2 nathanw int rv = 0, s;
1512 1.28.8.2 nathanw struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
1513 1.28.8.2 nathanw struct fd_type *type = fd->sc_type;
1514 1.28.8.2 nathanw struct buf *bp;
1515 1.28.8.2 nathanw
1516 1.28.8.2 nathanw /* set up a buffer header for fdstrategy() */
1517 1.28.8.2 nathanw bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1518 1.28.8.2 nathanw if(bp == 0)
1519 1.28.8.2 nathanw return ENOBUFS;
1520 1.28.8.2 nathanw bzero((void *)bp, sizeof(struct buf));
1521 1.28.8.2 nathanw bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1522 1.28.8.2 nathanw bp->b_proc = p;
1523 1.28.8.2 nathanw bp->b_dev = dev;
1524 1.28.8.2 nathanw
1525 1.28.8.2 nathanw /*
1526 1.28.8.2 nathanw * calculate a fake blkno, so fdstrategy() would initiate a
1527 1.28.8.2 nathanw * seek to the requested cylinder
1528 1.28.8.2 nathanw */
1529 1.28.8.2 nathanw bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1530 1.28.8.2 nathanw + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1531 1.28.8.2 nathanw
1532 1.28.8.2 nathanw bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1533 1.28.8.2 nathanw bp->b_data = (caddr_t)finfo;
1534 1.28.8.2 nathanw
1535 1.28.8.2 nathanw #ifdef DEBUG
1536 1.28.8.2 nathanw printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount);
1537 1.28.8.2 nathanw #endif
1538 1.28.8.2 nathanw
1539 1.28.8.2 nathanw /* now do the format */
1540 1.28.8.2 nathanw fdstrategy(bp);
1541 1.28.8.2 nathanw
1542 1.28.8.2 nathanw /* ...and wait for it to complete */
1543 1.28.8.2 nathanw s = splbio();
1544 1.28.8.2 nathanw while(!(bp->b_flags & B_DONE)) {
1545 1.28.8.2 nathanw rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
1546 1.28.8.2 nathanw if (rv == EWOULDBLOCK)
1547 1.28.8.2 nathanw break;
1548 1.28.8.2 nathanw }
1549 1.28.8.2 nathanw splx(s);
1550 1.28.8.2 nathanw
1551 1.28.8.2 nathanw if (rv == EWOULDBLOCK) {
1552 1.28.8.2 nathanw /* timed out */
1553 1.28.8.2 nathanw rv = EIO;
1554 1.28.8.2 nathanw biodone(bp);
1555 1.28.8.2 nathanw }
1556 1.28.8.2 nathanw if(bp->b_flags & B_ERROR) {
1557 1.28.8.2 nathanw rv = bp->b_error;
1558 1.28.8.2 nathanw }
1559 1.28.8.2 nathanw free(bp, M_TEMP);
1560 1.28.8.2 nathanw return rv;
1561 1.28.8.2 nathanw }
1562 1.28.8.2 nathanw
1563 1.28.8.2 nathanw
1564 1.28.8.2 nathanw /*
1565 1.28.8.2 nathanw * Obtain a disklabel. Either a real one from the disk or, if there
1566 1.28.8.2 nathanw * is none, a fake one.
1567 1.28.8.2 nathanw */
1568 1.28.8.2 nathanw static void
1569 1.28.8.2 nathanw fdgetdisklabel(fd, dev)
1570 1.28.8.2 nathanw struct fd_softc *fd;
1571 1.28.8.2 nathanw dev_t dev;
1572 1.28.8.2 nathanw {
1573 1.28.8.2 nathanw struct disklabel *lp;
1574 1.28.8.2 nathanw struct cpu_disklabel cpulab;
1575 1.28.8.2 nathanw
1576 1.28.8.2 nathanw if (fd->sc_flags & FD_HAVELAB)
1577 1.28.8.2 nathanw return; /* Already got one */
1578 1.28.8.2 nathanw
1579 1.28.8.2 nathanw lp = fd->sc_dk.dk_label;
1580 1.28.8.2 nathanw
1581 1.28.8.2 nathanw bzero(lp, sizeof(*lp));
1582 1.28.8.2 nathanw bzero(&cpulab, sizeof(cpulab));
1583 1.28.8.2 nathanw
1584 1.28.8.2 nathanw lp->d_secpercyl = fd->sc_type->seccyl;
1585 1.28.8.2 nathanw lp->d_type = DTYPE_FLOPPY;
1586 1.28.8.2 nathanw lp->d_secsize = FDC_BSIZE;
1587 1.28.8.2 nathanw lp->d_secperunit = fd->sc_type->size;
1588 1.28.8.2 nathanw
1589 1.28.8.2 nathanw /*
1590 1.28.8.2 nathanw * If there is no label on the disk: fake one
1591 1.28.8.2 nathanw */
1592 1.28.8.2 nathanw if (readdisklabel(dev, fdstrategy, lp, &cpulab) != NULL)
1593 1.28.8.2 nathanw fdgetdefaultlabel(fd, lp, RAW_PART);
1594 1.28.8.2 nathanw fd->sc_flags |= FD_HAVELAB;
1595 1.28.8.2 nathanw
1596 1.28.8.2 nathanw if ((FDC_BSIZE * fd->sc_type->size)
1597 1.28.8.2 nathanw < (lp->d_secsize * lp->d_secperunit)) {
1598 1.28.8.2 nathanw /*
1599 1.28.8.2 nathanw * XXX: Ignore these fields. If you drop a vnddisk
1600 1.28.8.2 nathanw * on more than one floppy, you'll get disturbing
1601 1.28.8.2 nathanw * sounds!
1602 1.28.8.2 nathanw */
1603 1.28.8.2 nathanw lp->d_secpercyl = fd->sc_type->seccyl;
1604 1.28.8.2 nathanw lp->d_type = DTYPE_FLOPPY;
1605 1.28.8.2 nathanw lp->d_secsize = FDC_BSIZE;
1606 1.28.8.2 nathanw lp->d_secperunit = fd->sc_type->size;
1607 1.28.8.2 nathanw }
1608 1.28.8.2 nathanw }
1609 1.28.8.2 nathanw
1610 1.28.8.2 nathanw /*
1611 1.28.8.2 nathanw * Build defaultdisk label. For now we only create a label from what we
1612 1.28.8.2 nathanw * know from 'sc'.
1613 1.28.8.2 nathanw */
1614 1.28.8.2 nathanw static void
1615 1.28.8.2 nathanw fdgetdefaultlabel(fd, lp, part)
1616 1.28.8.2 nathanw struct fd_softc *fd;
1617 1.28.8.2 nathanw struct disklabel *lp;
1618 1.28.8.2 nathanw int part;
1619 1.28.8.2 nathanw {
1620 1.28.8.2 nathanw bzero(lp, sizeof(struct disklabel));
1621 1.28.8.2 nathanw
1622 1.28.8.2 nathanw lp->d_secsize = 128 * (1 << fd->sc_type->secsize);
1623 1.28.8.2 nathanw lp->d_ntracks = fd->sc_type->heads;
1624 1.28.8.2 nathanw lp->d_nsectors = fd->sc_type->sectrac;
1625 1.28.8.2 nathanw lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1626 1.28.8.2 nathanw lp->d_ncylinders = fd->sc_type->size / lp->d_secpercyl;
1627 1.28.8.2 nathanw lp->d_secperunit = fd->sc_type->size;
1628 1.28.8.2 nathanw
1629 1.28.8.2 nathanw lp->d_type = DTYPE_FLOPPY;
1630 1.28.8.2 nathanw lp->d_rpm = 300; /* good guess I suppose. */
1631 1.28.8.2 nathanw lp->d_interleave = 1; /* FIXME: is this OK? */
1632 1.28.8.2 nathanw lp->d_bbsize = 0;
1633 1.28.8.2 nathanw lp->d_sbsize = 0;
1634 1.28.8.2 nathanw lp->d_npartitions = part + 1;
1635 1.28.8.2 nathanw lp->d_trkseek = 6000; /* Who cares... */
1636 1.28.8.2 nathanw lp->d_magic = DISKMAGIC;
1637 1.28.8.2 nathanw lp->d_magic2 = DISKMAGIC;
1638 1.28.8.2 nathanw lp->d_checksum = dkcksum(lp);
1639 1.28.8.2 nathanw lp->d_partitions[part].p_size = lp->d_secperunit;
1640 1.28.8.2 nathanw lp->d_partitions[part].p_fstype = FS_UNUSED;
1641 1.28.8.2 nathanw lp->d_partitions[part].p_fsize = 1024;
1642 1.28.8.2 nathanw lp->d_partitions[part].p_frag = 8;
1643 1.28.8.2 nathanw }
1644