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