fd.c revision 1.80.2.1 1 /* $NetBSD: fd.c,v 1.80.2.1 2008/03/24 07:15:29 keiichi Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*-
40 * Copyright (c) 1990 The Regents of the University of California.
41 * All rights reserved.
42 *
43 * This code is derived from software contributed to Berkeley by
44 * Don Ahn.
45 *
46 * Redistribution and use in source and binary forms, with or without
47 * modification, are permitted provided that the following conditions
48 * are met:
49 * 1. Redistributions of source code must retain the above copyright
50 * notice, this list of conditions and the following disclaimer.
51 * 2. Redistributions in binary form must reproduce the above copyright
52 * notice, this list of conditions and the following disclaimer in the
53 * documentation and/or other materials provided with the distribution.
54 * 3. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE.
69 *
70 * @(#)fd.c 7.4 (Berkeley) 5/25/91
71 */
72
73 /*
74 * Floppy formatting facilities merged from FreeBSD fd.c driver:
75 * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
76 * which carries the same copyright/redistribution notice as shown above with
77 * the addition of the following statement before the "Redistribution and
78 * use ..." clause:
79 *
80 * Copyright (c) 1993, 1994 by
81 * jc (at) irbs.UUCP (John Capo)
82 * vak (at) zebub.msk.su (Serge Vakulenko)
83 * ache (at) astral.msk.su (Andrew A. Chernov)
84 *
85 * Copyright (c) 1993, 1994, 1995 by
86 * joerg_wunsch (at) uriah.sax.de (Joerg Wunsch)
87 * dufault (at) hda.com (Peter Dufault)
88 */
89
90 #include <sys/cdefs.h>
91 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.80.2.1 2008/03/24 07:15:29 keiichi Exp $");
92
93 #include "rnd.h"
94 #include "opt_ddb.h"
95
96 /*
97 * XXX This driver should be properly MI'd some day, but this allows us
98 * XXX to eliminate a lot of code duplication for now.
99 */
100 #if !defined(alpha) && !defined(algor) && !defined(atari) && \
101 !defined(bebox) && !defined(evbmips) && !defined(i386) && \
102 !defined(prep) && !defined(sandpoint) && !defined(x86_64)
103 #error platform not supported by this driver, yet
104 #endif
105
106 #include <sys/param.h>
107 #include <sys/systm.h>
108 #include <sys/callout.h>
109 #include <sys/kernel.h>
110 #include <sys/file.h>
111 #include <sys/ioctl.h>
112 #include <sys/device.h>
113 #include <sys/disklabel.h>
114 #include <sys/disk.h>
115 #include <sys/buf.h>
116 #include <sys/bufq.h>
117 #include <sys/malloc.h>
118 #include <sys/uio.h>
119 #include <sys/syslog.h>
120 #include <sys/queue.h>
121 #include <sys/proc.h>
122 #include <sys/fdio.h>
123 #include <sys/conf.h>
124 #include <sys/vnode.h>
125 #if NRND > 0
126 #include <sys/rnd.h>
127 #endif
128
129 #include <prop/proplib.h>
130
131 #include <uvm/uvm_extern.h>
132
133 #include <dev/cons.h>
134
135 #include <sys/cpu.h>
136 #include <sys/bus.h>
137
138 #include "locators.h"
139
140 #if defined(atari)
141 /*
142 * On the atari, it is configured as fdcisa
143 */
144 #define FDCCF_DRIVE FDCISACF_DRIVE
145 #define FDCCF_DRIVE_DEFAULT FDCISACF_DRIVE_DEFAULT
146
147 #define fd_cd fdisa_cd
148 #endif /* atari */
149
150 #include <sys/intr.h>
151
152 #include <dev/isa/isavar.h>
153 #include <dev/isa/isadmavar.h>
154
155 #include <dev/isa/fdreg.h>
156 #include <dev/isa/fdcvar.h>
157
158 #if defined(i386)
159
160 #include <dev/ic/mc146818reg.h> /* for NVRAM access */
161 #include <i386/isa/nvram.h>
162
163 #include "mca.h"
164 #if NMCA > 0
165 #include <machine/mca_machdep.h> /* for MCA_system */
166 #endif
167
168 #endif /* i386 */
169
170 #include <dev/isa/fdvar.h>
171
172 #define FDUNIT(dev) (minor(dev) / 8)
173 #define FDTYPE(dev) (minor(dev) % 8)
174
175 /* (mis)use device use flag to identify format operation */
176 #define B_FORMAT B_DEVPRIVATE
177
178 /* controller driver configuration */
179 int fdprint(void *, const char *);
180
181 #if NMCA > 0
182 /* MCA - specific entries */
183 const struct fd_type mca_fd_types[] = {
184 { 18,2,36,2,0xff,0x0f,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette - XXX try 16ms step rate */
185 { 9,2,18,2,0xff,0x4f,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5 inch 720kB diskette - XXX try 24ms step rate */
186 };
187 #endif /* NMCA > 0 */
188
189 /* The order of entries in the following table is important -- BEWARE! */
190
191 #if defined(atari)
192 const struct fd_type fd_types[] = {
193 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */
194 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5 inch 720kB diskette */
195 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */
196 };
197 #else
198 const struct fd_type fd_types[] = {
199 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */
200 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB" }, /* 1.2 MB AT-diskettes */
201 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */
202 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */
203 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5 inch 720kB diskette */
204 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x" }, /* 720kB in 1.2MB drive */
205 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */
206 };
207 #endif /* defined(atari) */
208
209 void fdcfinishattach(device_t);
210 int fdprobe(device_t, struct cfdata *, void *);
211 void fdattach(device_t, device_t, void *);
212 static int fddetach(device_t, int);
213 static int fdcintr1(struct fdc_softc *);
214 static void fdcintrcb(void *);
215 static bool fdcsuspend(device_t PMF_FN_PROTO);
216 static bool fdcresume(device_t PMF_FN_PROTO);
217
218 extern struct cfdriver fd_cd;
219
220 #ifdef atari
221 CFATTACH_DECL_NEW(fdisa, sizeof(struct fd_softc),
222 fdprobe, fdattach, fddetach, NULL);
223 #else
224 CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc),
225 fdprobe, fdattach, fddetach, NULL);
226 #endif
227
228 dev_type_open(fdopen);
229 dev_type_close(fdclose);
230 dev_type_read(fdread);
231 dev_type_write(fdwrite);
232 dev_type_ioctl(fdioctl);
233 dev_type_strategy(fdstrategy);
234
235 const struct bdevsw fd_bdevsw = {
236 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
237 };
238
239 const struct cdevsw fd_cdevsw = {
240 fdopen, fdclose, fdread, fdwrite, fdioctl,
241 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
242 };
243
244 void fdgetdisklabel(struct fd_softc *);
245 int fd_get_parms(struct fd_softc *);
246 void fdstart(struct fd_softc *);
247
248 struct dkdriver fddkdriver = { fdstrategy, NULL };
249
250 #if defined(i386)
251 const struct fd_type *fd_nvtotype(const char *, int, int);
252 #endif /* i386 */
253 void fd_set_motor(struct fdc_softc *fdc, int reset);
254 void fd_motor_off(void *arg);
255 void fd_motor_on(void *arg);
256 int fdcresult(struct fdc_softc *fdc);
257 void fdcstart(struct fdc_softc *fdc);
258 void fdcstatus(device_t, int, const char *);
259 void fdctimeout(void *arg);
260 void fdcretry(struct fdc_softc *fdc);
261 void fdfinish(struct fd_softc *fd, struct buf *bp);
262 static const struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
263 int fdformat(dev_t, struct ne7_fd_formb *, struct lwp *);
264 static void fd_set_properties(struct fd_softc *fd);
265
266 void fd_mountroot_hook(device_t);
267
268 /*
269 * Arguments passed between fdcattach and fdprobe.
270 */
271 struct fdc_attach_args {
272 int fa_drive;
273 const struct fd_type *fa_deftype;
274 };
275
276 /*
277 * Print the location of a disk drive (called just before attaching the
278 * the drive). If `fdc' is not NULL, the drive was found but was not
279 * in the system config file; print the drive name as well.
280 * Return QUIET (config_find ignores this if the device was configured) to
281 * avoid printing `fdN not configured' messages.
282 */
283 int
284 fdprint(void *aux, const char *fdc)
285 {
286 struct fdc_attach_args *fa = aux;
287
288 if (!fdc)
289 aprint_normal(" drive %d", fa->fa_drive);
290 return QUIET;
291 }
292
293 static bool
294 fdcresume(device_t self PMF_FN_ARGS)
295 {
296 struct fdc_softc *fdc = device_private(self);
297
298 (void)fdcintr1(fdc);
299 return true;
300 }
301
302 static bool
303 fdcsuspend(device_t self PMF_FN_ARGS)
304 {
305 struct fdc_softc *fdc = device_private(self);
306 int drive;
307 struct fd_softc *fd;
308
309 mutex_enter(&fdc->sc_mtx);
310 while (fdc->sc_state != DEVIDLE)
311 cv_wait(&fdc->sc_cv, &fdc->sc_mtx);
312 for (drive = 0; drive < 4; drive++) {
313 if ((fd = fdc->sc_fd[drive]) == NULL)
314 continue;
315 fd->sc_flags &= ~(FD_MOTOR|FD_MOTOR_WAIT);
316 }
317 fd_set_motor(fdc, 0);
318 mutex_exit(&fdc->sc_mtx);
319 return true;
320 }
321
322 void
323 fdc_childdet(device_t self, device_t child)
324 {
325 struct fdc_softc *fdc = device_private(self);
326 struct fd_softc *fd = device_private(child);
327 int drive = fd->sc_drive;
328
329 KASSERT(fdc->sc_fd[drive] == fd); /* but the kid is not my son */
330 fdc->sc_fd[drive] = NULL;
331 }
332
333 int
334 fdcdetach(device_t self, int flags)
335 {
336 int rc;
337 struct fdc_softc *fdc = device_private(self);
338
339 if ((rc = config_detach_children(self, flags)) != 0)
340 return rc;
341
342 pmf_device_deregister(self);
343
344 isa_dmamap_destroy(fdc->sc_ic, fdc->sc_drq);
345 isa_drq_free(fdc->sc_ic, fdc->sc_drq);
346
347 callout_destroy(&fdc->sc_intr_ch);
348 callout_destroy(&fdc->sc_timo_ch);
349
350 cv_destroy(&fdc->sc_cv);
351 mutex_destroy(&fdc->sc_mtx);
352
353 return 0;
354 }
355
356 void
357 fdcattach(struct fdc_softc *fdc)
358 {
359 mutex_init(&fdc->sc_mtx, MUTEX_DEFAULT, IPL_BIO);
360 cv_init(&fdc->sc_cv, "fdcwakeup");
361 callout_init(&fdc->sc_timo_ch, 0);
362 callout_init(&fdc->sc_intr_ch, 0);
363
364 fdc->sc_state = DEVIDLE;
365 TAILQ_INIT(&fdc->sc_drives);
366
367 fdc->sc_maxiosize = isa_dmamaxsize(fdc->sc_ic, fdc->sc_drq);
368
369 if (isa_drq_alloc(fdc->sc_ic, fdc->sc_drq) != 0) {
370 aprint_normal_dev(fdc->sc_dev, "can't reserve drq %d\n",
371 fdc->sc_drq);
372 return;
373 }
374
375 if (isa_dmamap_create(fdc->sc_ic, fdc->sc_drq, fdc->sc_maxiosize,
376 BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
377 aprint_normal_dev(fdc->sc_dev, "can't set up ISA DMA map\n");
378 return;
379 }
380
381 config_interrupts(fdc->sc_dev, fdcfinishattach);
382
383 if (!pmf_device_register(fdc->sc_dev, fdcsuspend, fdcresume)) {
384 aprint_error_dev(fdc->sc_dev,
385 "cannot set power mgmt handler\n");
386 }
387 }
388
389 void
390 fdcfinishattach(device_t self)
391 {
392 struct fdc_softc *fdc = device_private(self);
393 bus_space_tag_t iot = fdc->sc_iot;
394 bus_space_handle_t ioh = fdc->sc_ioh;
395 struct fdc_attach_args fa;
396 #if defined(i386)
397 int type;
398 #endif
399
400 /*
401 * Reset the controller to get it into a known state. Not all
402 * probes necessarily need do this to discover the controller up
403 * front, so don't assume anything.
404 */
405
406 bus_space_write_1(iot, ioh, fdout, 0);
407 delay(100);
408 bus_space_write_1(iot, ioh, fdout, FDO_FRST);
409
410 /* see if it can handle a command */
411 if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0) {
412 aprint_normal_dev(fdc->sc_dev, "can't reset controller\n");
413 return;
414 }
415 out_fdc(iot, ioh, 0xdf);
416 out_fdc(iot, ioh, 2);
417
418 #if defined(i386)
419 /*
420 * The NVRAM info only tells us about the first two disks on the
421 * `primary' floppy controller.
422 */
423 /* XXX device_unit() abuse */
424 if (device_unit(fdc->sc_dev) == 0)
425 type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */
426 else
427 type = -1;
428 #endif /* i386 */
429
430 /* physical limit: four drives per controller. */
431 fdc->sc_state = PROBING;
432 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
433 if (fdc->sc_known) {
434 if (fdc->sc_present & (1 << fa.fa_drive)) {
435 fa.fa_deftype = fdc->sc_knownfds[fa.fa_drive];
436 config_found(fdc->sc_dev, (void *)&fa,
437 fdprint);
438 }
439 } else {
440 #if defined(i386)
441 if (type >= 0 && fa.fa_drive < 2)
442 fa.fa_deftype =
443 fd_nvtotype(device_xname(fdc->sc_dev),
444 type, fa.fa_drive);
445 else
446 fa.fa_deftype = NULL; /* unknown */
447 #elif defined(atari)
448 /*
449 * Atari has a different ordening, defaults to 1.44
450 */
451 fa.fa_deftype = &fd_types[2];
452 #else
453 /*
454 * Default to 1.44MB on Alpha and BeBox. How do we tell
455 * on these platforms?
456 */
457 fa.fa_deftype = &fd_types[0];
458 #endif /* i386 */
459 (void)config_found_ia(fdc->sc_dev, "fdc", (void *)&fa, fdprint);
460 }
461 }
462 fdc->sc_state = DEVIDLE;
463 }
464
465 int
466 fdprobe(device_t parent, cfdata_t match, void *aux)
467 {
468 struct fdc_softc *fdc = device_private(parent);
469 struct cfdata *cf = match;
470 struct fdc_attach_args *fa = aux;
471 int drive = fa->fa_drive;
472 bus_space_tag_t iot = fdc->sc_iot;
473 bus_space_handle_t ioh = fdc->sc_ioh;
474 int n;
475
476 if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT &&
477 cf->cf_loc[FDCCF_DRIVE] != drive)
478 return 0;
479 /*
480 * XXX
481 * This is to work around some odd interactions between this driver
482 * and SMC Ethernet cards.
483 */
484 if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2)
485 return 0;
486
487 /* Use PNP information if available */
488 if (fdc->sc_known)
489 return 1;
490
491 mutex_enter(&fdc->sc_mtx);
492 /* toss any interrupt status */
493 for (n = 0; n < 4; n++) {
494 out_fdc(iot, ioh, NE7CMD_SENSEI);
495 (void) fdcresult(fdc);
496 }
497 /* select drive and turn on motor */
498 bus_space_write_1(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive));
499 /* wait for motor to spin up */
500 /* XXX check sc_probe */
501 (void) cv_timedwait(&fdc->sc_cv, &fdc->sc_mtx, hz / 4);
502 out_fdc(iot, ioh, NE7CMD_RECAL);
503 out_fdc(iot, ioh, drive);
504 /* wait for recalibrate, up to 2s */
505 /* XXX check sc_probe */
506 if (cv_timedwait(&fdc->sc_cv, &fdc->sc_mtx, 2 * hz) != EWOULDBLOCK){
507 #ifdef FD_DEBUG
508 /* XXX */
509 printf("fdprobe: got intr\n");
510 #endif
511 }
512 out_fdc(iot, ioh, NE7CMD_SENSEI);
513 n = fdcresult(fdc);
514 #ifdef FD_DEBUG
515 {
516 int i;
517 printf("fdprobe: status");
518 for (i = 0; i < n; i++)
519 printf(" %x", fdc->sc_status[i]);
520 printf("\n");
521 }
522 #endif
523 /* turn off motor */
524 bus_space_write_1(iot, ioh, fdout, FDO_FRST);
525 mutex_exit(&fdc->sc_mtx);
526
527 #if defined(bebox) /* XXX What is this about? --thorpej (at) NetBSD.org */
528 if (n != 2 || (fdc->sc_status[1] != 0))
529 return 0;
530 #else
531 if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
532 return 0;
533 #endif /* bebox */
534
535 return 1;
536 }
537
538 /*
539 * Controller is working, and drive responded. Attach it.
540 */
541 void
542 fdattach(device_t parent, device_t self, void *aux)
543 {
544 struct fdc_softc *fdc = device_private(parent);
545 struct fd_softc *fd = device_private(self);
546 struct fdc_attach_args *fa = aux;
547 const struct fd_type *type = fa->fa_deftype;
548 int drive = fa->fa_drive;
549
550 fd->sc_dev = self;
551
552 callout_init(&fd->sc_motoron_ch, 0);
553 callout_init(&fd->sc_motoroff_ch, 0);
554
555 /* XXX Allow `flags' to override device type? */
556
557 if (type)
558 aprint_normal(": %s, %d cyl, %d head, %d sec\n", type->name,
559 type->cyls, type->heads, type->sectrac);
560 else
561 aprint_normal(": density unknown\n");
562
563 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
564 fd->sc_cylin = -1;
565 fd->sc_drive = drive;
566 fd->sc_deftype = type;
567 fdc->sc_fd[drive] = fd;
568
569 /*
570 * Initialize and attach the disk structure.
571 */
572 disk_init(&fd->sc_dk, device_xname(fd->sc_dev), &fddkdriver);
573 disk_attach(&fd->sc_dk);
574
575 /*
576 * Establish a mountroot hook.
577 */
578 fd->sc_roothook =
579 mountroothook_establish(fd_mountroot_hook, fd->sc_dev);
580
581 #if NRND > 0
582 rnd_attach_source(&fd->rnd_source, device_xname(fd->sc_dev),
583 RND_TYPE_DISK, 0);
584 #endif
585
586 fd_set_properties(fd);
587
588 if (!pmf_device_register(self, NULL, NULL))
589 aprint_error_dev(self, "cannot set power mgmt handler\n");
590 }
591
592 static int
593 fddetach(device_t self, int flags)
594 {
595 struct fd_softc *fd = device_private(self);
596 int bmaj, cmaj, i, mn;
597
598 fd_motor_off(fd);
599
600 /* locate the major number */
601 bmaj = bdevsw_lookup_major(&fd_bdevsw);
602 cmaj = cdevsw_lookup_major(&fd_cdevsw);
603
604 /* Nuke the vnodes for any open instances. */
605 for (i = 0; i < MAXPARTITIONS; i++) {
606 mn = DISKMINOR(device_unit(self), i);
607 vdevgone(bmaj, mn, mn, VBLK);
608 vdevgone(cmaj, mn, mn, VCHR);
609 }
610
611 pmf_device_deregister(self);
612
613 #if 0 /* XXX need to undo at detach? */
614 fd_set_properties(fd);
615 #endif
616 #if NRND > 0
617 rnd_detach_source(&fd->rnd_source);
618 #endif
619
620 disk_detach(&fd->sc_dk);
621
622 /* Kill off any queued buffers. */
623 bufq_drain(fd->sc_q);
624
625 bufq_free(fd->sc_q);
626
627 callout_destroy(&fd->sc_motoroff_ch);
628 callout_destroy(&fd->sc_motoron_ch);
629
630 return 0;
631 }
632
633 #if defined(i386)
634 /*
635 * Translate nvram type into internal data structure. Return NULL for
636 * none/unknown/unusable.
637 */
638 const struct fd_type *
639 fd_nvtotype(const char *fdc, int nvraminfo, int drive)
640 {
641 int type;
642
643 type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
644 switch (type) {
645 case NVRAM_DISKETTE_NONE:
646 return NULL;
647 case NVRAM_DISKETTE_12M:
648 return &fd_types[1];
649 case NVRAM_DISKETTE_TYPE5:
650 case NVRAM_DISKETTE_TYPE6:
651 /* XXX We really ought to handle 2.88MB format. */
652 case NVRAM_DISKETTE_144M:
653 #if NMCA > 0
654 if (MCA_system)
655 return &mca_fd_types[0];
656 else
657 #endif /* NMCA > 0 */
658 return &fd_types[0];
659 case NVRAM_DISKETTE_360K:
660 return &fd_types[3];
661 case NVRAM_DISKETTE_720K:
662 #if NMCA > 0
663 if (MCA_system)
664 return &mca_fd_types[1];
665 else
666 #endif /* NMCA > 0 */
667 return &fd_types[4];
668 default:
669 printf("%s: drive %d: unknown device type 0x%x\n",
670 fdc, drive, type);
671 return NULL;
672 }
673 }
674 #endif /* i386 */
675
676 static const struct fd_type *
677 fd_dev_to_type(struct fd_softc *fd, dev_t dev)
678 {
679 u_int type = FDTYPE(dev);
680
681 if (type > __arraycount(fd_types))
682 return NULL;
683 return type ? &fd_types[type - 1] : fd->sc_deftype;
684 }
685
686 void
687 fdstrategy(struct buf *bp)
688 {
689 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(bp->b_dev));
690 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
691 int sz;
692
693 /* Valid unit, controller, and request? */
694 if (bp->b_blkno < 0 ||
695 ((bp->b_bcount % FDC_BSIZE) != 0 &&
696 (bp->b_flags & B_FORMAT) == 0)) {
697 bp->b_error = EINVAL;
698 goto done;
699 }
700
701 /* If it's a null transfer, return immediately. */
702 if (bp->b_bcount == 0)
703 goto done;
704
705 sz = howmany(bp->b_bcount, FDC_BSIZE);
706
707 if (bp->b_blkno + sz > fd->sc_type->size) {
708 sz = fd->sc_type->size - bp->b_blkno;
709 if (sz == 0) {
710 /* If exactly at end of disk, return EOF. */
711 goto done;
712 }
713 if (sz < 0) {
714 /* If past end of disk, return EINVAL. */
715 bp->b_error = EINVAL;
716 goto done;
717 }
718 /* Otherwise, truncate request. */
719 bp->b_bcount = sz << DEV_BSHIFT;
720 }
721
722 bp->b_rawblkno = bp->b_blkno;
723 bp->b_cylinder =
724 bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
725
726 #ifdef FD_DEBUG
727 printf("fdstrategy: b_blkno %llu b_bcount %d blkno %llu cylin %d "
728 "sz %d\n", (unsigned long long)bp->b_blkno, bp->b_bcount,
729 (unsigned long long)fd->sc_blkno, bp->b_cylinder, sz);
730 #endif
731
732 /* Queue transfer on drive, activate drive and controller if idle. */
733 mutex_enter(&fdc->sc_mtx);
734 BUFQ_PUT(fd->sc_q, bp);
735 callout_stop(&fd->sc_motoroff_ch); /* a good idea */
736 if (fd->sc_active == 0)
737 fdstart(fd);
738 #ifdef DIAGNOSTIC
739 else {
740 if (fdc->sc_state == DEVIDLE) {
741 printf("fdstrategy: controller inactive\n");
742 fdcstart(fdc);
743 }
744 }
745 #endif
746 mutex_exit(&fdc->sc_mtx);
747 return;
748
749 done:
750 /* Toss transfer; we're done early. */
751 bp->b_resid = bp->b_bcount;
752 biodone(bp);
753 }
754
755 void
756 fdstart(struct fd_softc *fd)
757 {
758 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
759 int active = !TAILQ_EMPTY(&fdc->sc_drives);
760
761 KASSERT(mutex_owned(&fdc->sc_mtx));
762 /* Link into controller queue. */
763 fd->sc_active = 1;
764 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
765
766 /* If controller not already active, start it. */
767 if (!active)
768 fdcstart(fdc);
769 }
770
771 void
772 fdfinish(struct fd_softc *fd, struct buf *bp)
773 {
774 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
775
776 /*
777 * Move this drive to the end of the queue to give others a `fair'
778 * chance. We only force a switch if N operations are completed while
779 * another drive is waiting to be serviced, since there is a long motor
780 * startup delay whenever we switch.
781 */
782 (void)BUFQ_GET(fd->sc_q);
783 if (TAILQ_NEXT(fd, sc_drivechain) && ++fd->sc_ops >= 8) {
784 fd->sc_ops = 0;
785 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
786 if (BUFQ_PEEK(fd->sc_q) != NULL)
787 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
788 else
789 fd->sc_active = 0;
790 }
791 bp->b_resid = fd->sc_bcount;
792 fd->sc_skip = 0;
793
794 #if NRND > 0
795 rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
796 #endif
797
798 biodone(bp);
799 /* turn off motor 5s from now */
800 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
801 fdc->sc_state = DEVIDLE;
802 }
803
804 int
805 fdread(dev_t dev, struct uio *uio, int flags)
806 {
807
808 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
809 }
810
811 int
812 fdwrite(dev_t dev, struct uio *uio, int flags)
813 {
814
815 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
816 }
817
818 void
819 fd_set_motor(struct fdc_softc *fdc, int reset)
820 {
821 struct fd_softc *fd;
822 u_char status;
823 int n;
824
825 if ((fd = TAILQ_FIRST(&fdc->sc_drives)) != NULL)
826 status = fd->sc_drive;
827 else
828 status = 0;
829 if (!reset)
830 status |= FDO_FRST | FDO_FDMAEN;
831 for (n = 0; n < 4; n++)
832 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
833 status |= FDO_MOEN(n);
834 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, status);
835 }
836
837 void
838 fd_motor_off(void *arg)
839 {
840 struct fd_softc *fd = arg;
841 struct fdc_softc *fdc;
842
843 fdc = device_private(device_parent(fd->sc_dev));
844
845 mutex_enter(&fdc->sc_mtx);
846 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
847 fd_set_motor(fdc, 0);
848 mutex_exit(&fdc->sc_mtx);
849 }
850
851 void
852 fd_motor_on(void *arg)
853 {
854 struct fd_softc *fd = arg;
855 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
856
857 mutex_enter(&fdc->sc_mtx);
858 fd->sc_flags &= ~FD_MOTOR_WAIT;
859 if (TAILQ_FIRST(&fdc->sc_drives) == fd && fdc->sc_state == MOTORWAIT)
860 (void)fdcintr1(fdc);
861 mutex_exit(&fdc->sc_mtx);
862 }
863
864 int
865 fdcresult(struct fdc_softc *fdc)
866 {
867 bus_space_tag_t iot = fdc->sc_iot;
868 bus_space_handle_t ioh = fdc->sc_ioh;
869 u_char i;
870 u_int j = 100000,
871 n = 0;
872
873 for (; j; j--) {
874 i = bus_space_read_1(iot, ioh, fdsts) &
875 (NE7_DIO | NE7_RQM | NE7_CB);
876 if (i == NE7_RQM)
877 return n;
878 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
879 if (n >= sizeof(fdc->sc_status)) {
880 log(LOG_ERR, "fdcresult: overrun\n");
881 return -1;
882 }
883 fdc->sc_status[n++] =
884 bus_space_read_1(iot, ioh, fddata);
885 }
886 delay(10);
887 }
888 log(LOG_ERR, "fdcresult: timeout\n");
889 return -1;
890 }
891
892 int
893 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
894 {
895 u_char i;
896 u_int j = 100000;
897
898 for (; j; j--) {
899 i = bus_space_read_1(iot, ioh, fdsts) &
900 (NE7_DIO | NE7_RQM);
901 if (i == NE7_RQM) {
902 bus_space_write_1(iot, ioh, fddata, x);
903 return 0;
904 }
905 delay(10);
906 }
907 return -1;
908 }
909
910 int
911 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
912 {
913 struct fd_softc *fd;
914 const struct fd_type *type;
915
916 fd = device_lookup_private(&fd_cd, FDUNIT(dev));
917 if (fd == NULL)
918 return (ENXIO);
919
920 type = fd_dev_to_type(fd, dev);
921 if (type == NULL)
922 return ENXIO;
923
924 if ((fd->sc_flags & FD_OPEN) != 0 &&
925 memcmp(fd->sc_type, type, sizeof(*type)))
926 return EBUSY;
927
928 fd->sc_type_copy = *type;
929 fd->sc_type = &fd->sc_type_copy;
930 fd->sc_cylin = -1;
931 fd->sc_flags |= FD_OPEN;
932
933 fd_set_properties(fd);
934
935 return 0;
936 }
937
938 int
939 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
940 {
941 struct fd_softc *fd =
942 device_lookup_private(&fd_cd, FDUNIT(dev));
943
944 fd->sc_flags &= ~FD_OPEN;
945 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
946 return 0;
947 }
948
949 void
950 fdcstart(struct fdc_softc *fdc)
951 {
952
953 KASSERT(mutex_owned(&fdc->sc_mtx));
954
955 if (!device_is_active(fdc->sc_dev))
956 return;
957
958 #ifdef DIAGNOSTIC
959 /* only got here if controller's drive queue was inactive; should
960 be in idle state */
961 if (fdc->sc_state != DEVIDLE) {
962 printf("fdcstart: not idle\n");
963 return;
964 }
965 #endif
966 (void)fdcintr1(fdc);
967 }
968
969 void
970 fdcstatus(device_t dv, int n, const char *s)
971 {
972 struct fdc_softc *fdc = device_private(device_parent(dv));
973 char bits[64];
974
975 if (n == 0) {
976 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
977 (void) fdcresult(fdc);
978 n = 2;
979 }
980
981 aprint_normal_dev(dv, "%s", s);
982
983 switch (n) {
984 case 0:
985 printf("\n");
986 break;
987 case 2:
988 printf(" (st0 %s cyl %d)\n",
989 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
990 bits, sizeof(bits)), fdc->sc_status[1]);
991 break;
992 case 7:
993 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
994 NE7_ST0BITS, bits, sizeof(bits)));
995 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
996 NE7_ST1BITS, bits, sizeof(bits)));
997 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
998 NE7_ST2BITS, bits, sizeof(bits)));
999 printf(" cyl %d head %d sec %d)\n",
1000 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1001 break;
1002 #ifdef DIAGNOSTIC
1003 default:
1004 printf("\nfdcstatus: weird size");
1005 break;
1006 #endif
1007 }
1008 }
1009
1010 void
1011 fdctimeout(void *arg)
1012 {
1013 struct fdc_softc *fdc = arg;
1014 struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives);
1015
1016 mutex_enter(&fdc->sc_mtx);
1017 #ifdef DEBUG
1018 log(LOG_ERR, "fdctimeout: state %d\n", fdc->sc_state);
1019 #endif
1020 fdcstatus(fd->sc_dev, 0, "timeout");
1021
1022 if (BUFQ_PEEK(fd->sc_q) != NULL)
1023 fdc->sc_state++;
1024 else
1025 fdc->sc_state = DEVIDLE;
1026
1027 (void)fdcintr1(fdc);
1028 mutex_exit(&fdc->sc_mtx);
1029 }
1030
1031 static int
1032 fdcintr1(struct fdc_softc *fdc)
1033 {
1034 #define st0 fdc->sc_status[0]
1035 #define cyl fdc->sc_status[1]
1036 struct fd_softc *fd;
1037 struct buf *bp;
1038 bus_space_tag_t iot = fdc->sc_iot;
1039 bus_space_handle_t ioh = fdc->sc_ioh;
1040 int read, head, sec, i, nblks;
1041 struct fd_type *type;
1042 struct ne7_fd_formb *finfo = NULL;
1043
1044 KASSERT(mutex_owned(&fdc->sc_mtx));
1045 if (fdc->sc_state == PROBING) {
1046 #ifdef DEBUG
1047 printf("fdcintr: got probe interrupt\n");
1048 #endif
1049 fdc->sc_probe++;
1050 goto out;
1051 }
1052
1053 loop:
1054 /* Is there a drive for the controller to do a transfer with? */
1055 fd = TAILQ_FIRST(&fdc->sc_drives);
1056 if (fd == NULL) {
1057 fdc->sc_state = DEVIDLE;
1058 goto out;
1059 }
1060
1061 /* Is there a transfer to this drive? If not, deactivate drive. */
1062 bp = BUFQ_PEEK(fd->sc_q);
1063 if (bp == NULL) {
1064 fd->sc_ops = 0;
1065 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1066 fd->sc_active = 0;
1067 goto loop;
1068 }
1069
1070 if (bp->b_flags & B_FORMAT)
1071 finfo = (struct ne7_fd_formb *)bp->b_data;
1072
1073 switch (fdc->sc_state) {
1074 case DEVIDLE:
1075 fdc->sc_errors = 0;
1076 fd->sc_skip = 0;
1077 fd->sc_bcount = bp->b_bcount;
1078 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1079 callout_stop(&fd->sc_motoroff_ch);
1080 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1081 fdc->sc_state = MOTORWAIT;
1082 return 1;
1083 }
1084 if ((fd->sc_flags & FD_MOTOR) == 0) {
1085 /* Turn on the motor, being careful about pairing. */
1086 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
1087 if (ofd && ofd->sc_flags & FD_MOTOR) {
1088 callout_stop(&ofd->sc_motoroff_ch);
1089 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1090 }
1091 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1092 fd_set_motor(fdc, 0);
1093 fdc->sc_state = MOTORWAIT;
1094 /* Allow .25s for motor to stabilize. */
1095 callout_reset(&fd->sc_motoron_ch, hz / 4,
1096 fd_motor_on, fd);
1097 return 1;
1098 }
1099 /* Make sure the right drive is selected. */
1100 fd_set_motor(fdc, 0);
1101
1102 /* fall through */
1103 case DOSEEK:
1104 doseek:
1105 if (fd->sc_cylin == bp->b_cylinder)
1106 goto doio;
1107
1108 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1109 out_fdc(iot, ioh, fd->sc_type->steprate);
1110 out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */
1111
1112 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1113 out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1114 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1115
1116 fd->sc_cylin = -1;
1117 fdc->sc_state = SEEKWAIT;
1118
1119 iostat_seek(fd->sc_dk.dk_stats);
1120 disk_busy(&fd->sc_dk);
1121
1122 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1123 return 1;
1124
1125 case DOIO:
1126 doio:
1127 type = fd->sc_type;
1128 if (finfo)
1129 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1130 (char *)finfo;
1131 sec = fd->sc_blkno % type->seccyl;
1132 nblks = type->seccyl - sec;
1133 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1134 nblks = min(nblks, fdc->sc_maxiosize / FDC_BSIZE);
1135 fd->sc_nblks = nblks;
1136 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
1137 head = sec / type->sectrac;
1138 sec -= head * type->sectrac;
1139 #ifdef DIAGNOSTIC
1140 {
1141 int block;
1142 block = (fd->sc_cylin * type->heads + head)
1143 * type->sectrac + sec;
1144 if (block != fd->sc_blkno) {
1145 printf("fdcintr: block %d != blkno "
1146 "%" PRId64 "\n", block, fd->sc_blkno);
1147 #ifdef DDB
1148 Debugger();
1149 #endif
1150 }
1151 }
1152 #endif
1153 read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE;
1154 isa_dmastart(fdc->sc_ic, fdc->sc_drq,
1155 (char *)bp->b_data + fd->sc_skip, fd->sc_nbytes,
1156 NULL, read | DMAMODE_DEMAND, BUS_DMA_NOWAIT);
1157 bus_space_write_1(iot, fdc->sc_fdctlioh, 0, type->rate);
1158 #ifdef FD_DEBUG
1159 printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1160 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1161 head, sec, nblks);
1162 #endif
1163 if (finfo) {
1164 /* formatting */
1165 if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
1166 fdc->sc_errors = 4;
1167 fdcretry(fdc);
1168 goto loop;
1169 }
1170 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1171 out_fdc(iot, ioh, finfo->fd_formb_secshift);
1172 out_fdc(iot, ioh, finfo->fd_formb_nsecs);
1173 out_fdc(iot, ioh, finfo->fd_formb_gaplen);
1174 out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
1175 } else {
1176 if (read)
1177 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1178 else
1179 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1180 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1181 out_fdc(iot, ioh, fd->sc_cylin); /* track */
1182 out_fdc(iot, ioh, head);
1183 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1184 out_fdc(iot, ioh, type->secsize);/* sector size */
1185 out_fdc(iot, ioh, type->sectrac);/* sectors/track */
1186 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1187 out_fdc(iot, ioh, type->datalen);/* data length */
1188 }
1189 fdc->sc_state = IOCOMPLETE;
1190
1191 disk_busy(&fd->sc_dk);
1192
1193 /* allow 2 seconds for operation */
1194 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1195 return 1; /* will return later */
1196
1197 case SEEKWAIT:
1198 callout_stop(&fdc->sc_timo_ch);
1199 fdc->sc_state = SEEKCOMPLETE;
1200 /* allow 1/50 second for heads to settle */
1201 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcintrcb, fdc);
1202 return 1;
1203
1204 case SEEKCOMPLETE:
1205 /* no data on seek */
1206 disk_unbusy(&fd->sc_dk, 0, 0);
1207
1208 /* Make sure seek really happened. */
1209 out_fdc(iot, ioh, NE7CMD_SENSEI);
1210 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1211 cyl != bp->b_cylinder * fd->sc_type->step) {
1212 #ifdef FD_DEBUG
1213 fdcstatus(&fd->sc_dev, 2, "seek failed");
1214 #endif
1215 fdcretry(fdc);
1216 goto loop;
1217 }
1218 fd->sc_cylin = bp->b_cylinder;
1219 goto doio;
1220
1221 case IOTIMEDOUT:
1222 isa_dmaabort(fdc->sc_ic, fdc->sc_drq);
1223 case SEEKTIMEDOUT:
1224 case RECALTIMEDOUT:
1225 case RESETTIMEDOUT:
1226 fdcretry(fdc);
1227 goto loop;
1228
1229 case IOCOMPLETE: /* IO DONE, post-analyze */
1230 callout_stop(&fdc->sc_timo_ch);
1231
1232 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
1233 (bp->b_flags & B_READ));
1234
1235 if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
1236 isa_dmaabort(fdc->sc_ic, fdc->sc_drq);
1237 #ifdef FD_DEBUG
1238 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1239 "read failed" : "write failed");
1240 printf("blkno %llu nblks %d\n",
1241 (unsigned long long)fd->sc_blkno, fd->sc_nblks);
1242 #endif
1243 fdcretry(fdc);
1244 goto loop;
1245 }
1246 isa_dmadone(fdc->sc_ic, fdc->sc_drq);
1247 if (fdc->sc_errors) {
1248 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1249 fd->sc_skip / FDC_BSIZE, NULL);
1250 printf("\n");
1251 fdc->sc_errors = 0;
1252 }
1253 fd->sc_blkno += fd->sc_nblks;
1254 fd->sc_skip += fd->sc_nbytes;
1255 fd->sc_bcount -= fd->sc_nbytes;
1256 if (!finfo && fd->sc_bcount > 0) {
1257 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1258 goto doseek;
1259 }
1260 fdfinish(fd, bp);
1261 goto loop;
1262
1263 case DORESET:
1264 /* try a reset, keep motor on */
1265 fd_set_motor(fdc, 1);
1266 delay(100);
1267 fd_set_motor(fdc, 0);
1268 fdc->sc_state = RESETCOMPLETE;
1269 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1270 return 1; /* will return later */
1271
1272 case RESETCOMPLETE:
1273 callout_stop(&fdc->sc_timo_ch);
1274 /* clear the controller output buffer */
1275 for (i = 0; i < 4; i++) {
1276 out_fdc(iot, ioh, NE7CMD_SENSEI);
1277 (void) fdcresult(fdc);
1278 }
1279
1280 /* fall through */
1281 case DORECAL:
1282 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1283 out_fdc(iot, ioh, fd->sc_drive);
1284 fdc->sc_state = RECALWAIT;
1285 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1286 return 1; /* will return later */
1287
1288 case RECALWAIT:
1289 callout_stop(&fdc->sc_timo_ch);
1290 fdc->sc_state = RECALCOMPLETE;
1291 /* allow 1/30 second for heads to settle */
1292 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcintrcb, fdc);
1293 return 1; /* will return later */
1294
1295 case RECALCOMPLETE:
1296 out_fdc(iot, ioh, NE7CMD_SENSEI);
1297 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1298 #ifdef FD_DEBUG
1299 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1300 #endif
1301 fdcretry(fdc);
1302 goto loop;
1303 }
1304 fd->sc_cylin = 0;
1305 goto doseek;
1306
1307 case MOTORWAIT:
1308 if (fd->sc_flags & FD_MOTOR_WAIT)
1309 return 1; /* time's not up yet */
1310 goto doseek;
1311
1312 default:
1313 fdcstatus(fd->sc_dev, 0, "stray interrupt");
1314 return 1;
1315 }
1316 #undef st0
1317 #undef cyl
1318
1319 out:
1320 cv_signal(&fdc->sc_cv);
1321 return 1;
1322 }
1323
1324 static void
1325 fdcintrcb(void *arg)
1326 {
1327 (void)fdcintr(arg);
1328 }
1329
1330 int
1331 fdcintr(void *arg)
1332 {
1333 int rc;
1334 struct fdc_softc *fdc = arg;
1335
1336 mutex_enter(&fdc->sc_mtx);
1337 rc = fdcintr1(fdc);
1338 mutex_exit(&fdc->sc_mtx);
1339 return rc;
1340 }
1341
1342 void
1343 fdcretry(struct fdc_softc *fdc)
1344 {
1345 char bits[64];
1346 struct fd_softc *fd;
1347 struct buf *bp;
1348
1349 fd = TAILQ_FIRST(&fdc->sc_drives);
1350 bp = BUFQ_PEEK(fd->sc_q);
1351
1352 if (fd->sc_opts & FDOPT_NORETRY)
1353 goto fail;
1354 switch (fdc->sc_errors) {
1355 case 0:
1356 /* try again */
1357 fdc->sc_state = DOSEEK;
1358 break;
1359
1360 case 1: case 2: case 3:
1361 /* didn't work; try recalibrating */
1362 fdc->sc_state = DORECAL;
1363 break;
1364
1365 case 4:
1366 /* still no go; reset the bastard */
1367 fdc->sc_state = DORESET;
1368 break;
1369
1370 default:
1371 fail:
1372 if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1373 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1374 fd->sc_skip / FDC_BSIZE, NULL);
1375
1376 printf(" (st0 %s",
1377 bitmask_snprintf(fdc->sc_status[0],
1378 NE7_ST0BITS, bits,
1379 sizeof(bits)));
1380 printf(" st1 %s",
1381 bitmask_snprintf(fdc->sc_status[1],
1382 NE7_ST1BITS, bits,
1383 sizeof(bits)));
1384 printf(" st2 %s",
1385 bitmask_snprintf(fdc->sc_status[2],
1386 NE7_ST2BITS, bits,
1387 sizeof(bits)));
1388 printf(" cyl %d head %d sec %d)\n",
1389 fdc->sc_status[3],
1390 fdc->sc_status[4],
1391 fdc->sc_status[5]);
1392 }
1393
1394 bp->b_error = EIO;
1395 fdfinish(fd, bp);
1396 }
1397 fdc->sc_errors++;
1398 }
1399
1400 int
1401 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1402 {
1403 struct fd_softc *fd =
1404 device_lookup_private(&fd_cd, FDUNIT(dev));
1405 struct fdformat_parms *form_parms;
1406 struct fdformat_cmd *form_cmd;
1407 struct ne7_fd_formb *fd_formb;
1408 struct disklabel buffer;
1409 int error;
1410 unsigned int scratch;
1411 int il[FD_MAX_NSEC + 1];
1412 int i, j;
1413 #ifdef __HAVE_OLD_DISKLABEL
1414 struct disklabel newlabel;
1415 #endif
1416
1417 switch (cmd) {
1418 case DIOCGDINFO:
1419 #ifdef __HAVE_OLD_DISKLABEL
1420 case ODIOCGDINFO:
1421 #endif
1422 memset(&buffer, 0, sizeof(buffer));
1423
1424 buffer.d_secpercyl = fd->sc_type->seccyl;
1425 buffer.d_type = DTYPE_FLOPPY;
1426 buffer.d_secsize = FDC_BSIZE;
1427
1428 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1429 return EINVAL;
1430
1431 #ifdef __HAVE_OLD_DISKLABEL
1432 if (cmd == ODIOCGDINFO) {
1433 if (buffer.d_npartitions > OLDMAXPARTITIONS)
1434 return ENOTTY;
1435 memcpy(addr, &buffer, sizeof (struct olddisklabel));
1436 } else
1437 #endif
1438 *(struct disklabel *)addr = buffer;
1439 return 0;
1440
1441 case DIOCWLABEL:
1442 if ((flag & FWRITE) == 0)
1443 return EBADF;
1444 /* XXX do something */
1445 return 0;
1446
1447 case DIOCWDINFO:
1448 #ifdef __HAVE_OLD_DISKLABEL
1449 case ODIOCWDINFO:
1450 #endif
1451 {
1452 struct disklabel *lp;
1453
1454 if ((flag & FWRITE) == 0)
1455 return EBADF;
1456 #ifdef __HAVE_OLD_DISKLABEL
1457 if (cmd == ODIOCWDINFO) {
1458 memset(&newlabel, 0, sizeof newlabel);
1459 memcpy(&newlabel, addr, sizeof (struct olddisklabel));
1460 lp = &newlabel;
1461 } else
1462 #endif
1463 lp = (struct disklabel *)addr;
1464
1465 error = setdisklabel(&buffer, lp, 0, NULL);
1466 if (error)
1467 return error;
1468
1469 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1470 return error;
1471 }
1472
1473 case FDIOCGETFORMAT:
1474 form_parms = (struct fdformat_parms *)addr;
1475 form_parms->fdformat_version = FDFORMAT_VERSION;
1476 form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1477 form_parms->ncyl = fd->sc_type->cyls;
1478 form_parms->nspt = fd->sc_type->sectrac;
1479 form_parms->ntrk = fd->sc_type->heads;
1480 form_parms->stepspercyl = fd->sc_type->step;
1481 form_parms->gaplen = fd->sc_type->gap2;
1482 form_parms->fillbyte = fd->sc_type->fillbyte;
1483 form_parms->interleave = fd->sc_type->interleave;
1484 switch (fd->sc_type->rate) {
1485 case FDC_500KBPS:
1486 form_parms->xfer_rate = 500 * 1024;
1487 break;
1488 case FDC_300KBPS:
1489 form_parms->xfer_rate = 300 * 1024;
1490 break;
1491 case FDC_250KBPS:
1492 form_parms->xfer_rate = 250 * 1024;
1493 break;
1494 default:
1495 return EINVAL;
1496 }
1497 return 0;
1498
1499 case FDIOCSETFORMAT:
1500 if((flag & FWRITE) == 0)
1501 return EBADF; /* must be opened for writing */
1502 form_parms = (struct fdformat_parms *)addr;
1503 if (form_parms->fdformat_version != FDFORMAT_VERSION)
1504 return EINVAL; /* wrong version of formatting prog */
1505
1506 scratch = form_parms->nbps >> 7;
1507 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1508 scratch & ~(1 << (ffs(scratch)-1)))
1509 /* not a power-of-two multiple of 128 */
1510 return EINVAL;
1511
1512 switch (form_parms->xfer_rate) {
1513 case 500 * 1024:
1514 fd->sc_type->rate = FDC_500KBPS;
1515 break;
1516 case 300 * 1024:
1517 fd->sc_type->rate = FDC_300KBPS;
1518 break;
1519 case 250 * 1024:
1520 fd->sc_type->rate = FDC_250KBPS;
1521 break;
1522 default:
1523 return EINVAL;
1524 }
1525
1526 if (form_parms->nspt > FD_MAX_NSEC ||
1527 form_parms->fillbyte > 0xff ||
1528 form_parms->interleave > 0xff)
1529 return EINVAL;
1530 fd->sc_type->sectrac = form_parms->nspt;
1531 if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1532 return EINVAL;
1533 fd->sc_type->heads = form_parms->ntrk;
1534 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1535 fd->sc_type->secsize = ffs(scratch)-1;
1536 fd->sc_type->gap2 = form_parms->gaplen;
1537 fd->sc_type->cyls = form_parms->ncyl;
1538 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1539 form_parms->nbps / DEV_BSIZE;
1540 fd->sc_type->step = form_parms->stepspercyl;
1541 fd->sc_type->fillbyte = form_parms->fillbyte;
1542 fd->sc_type->interleave = form_parms->interleave;
1543 return 0;
1544
1545 case FDIOCFORMAT_TRACK:
1546 if((flag & FWRITE) == 0)
1547 return EBADF; /* must be opened for writing */
1548 form_cmd = (struct fdformat_cmd *)addr;
1549 if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1550 return EINVAL; /* wrong version of formatting prog */
1551
1552 if (form_cmd->head >= fd->sc_type->heads ||
1553 form_cmd->cylinder >= fd->sc_type->cyls) {
1554 return EINVAL;
1555 }
1556
1557 fd_formb = malloc(sizeof(struct ne7_fd_formb),
1558 M_TEMP, M_NOWAIT);
1559 if (fd_formb == 0)
1560 return ENOMEM;
1561
1562 fd_formb->head = form_cmd->head;
1563 fd_formb->cyl = form_cmd->cylinder;
1564 fd_formb->transfer_rate = fd->sc_type->rate;
1565 fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1566 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1567 fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1568 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1569
1570 memset(il, 0, sizeof il);
1571 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1572 while (il[(j%fd_formb->fd_formb_nsecs)+1])
1573 j++;
1574 il[(j%fd_formb->fd_formb_nsecs)+1] = i;
1575 j += fd->sc_type->interleave;
1576 }
1577 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1578 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1579 fd_formb->fd_formb_headno(i) = form_cmd->head;
1580 fd_formb->fd_formb_secno(i) = il[i+1];
1581 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1582 }
1583
1584 error = fdformat(dev, fd_formb, l);
1585 free(fd_formb, M_TEMP);
1586 return error;
1587
1588 case FDIOCGETOPTS: /* get drive options */
1589 *(int *)addr = fd->sc_opts;
1590 return 0;
1591
1592 case FDIOCSETOPTS: /* set drive options */
1593 fd->sc_opts = *(int *)addr;
1594 return 0;
1595
1596 default:
1597 return ENOTTY;
1598 }
1599
1600 #ifdef DIAGNOSTIC
1601 panic("fdioctl: impossible");
1602 #endif
1603 }
1604
1605 int
1606 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l)
1607 {
1608 int rv = 0;
1609 struct fd_softc *fd =
1610 device_lookup_private(&fd_cd, FDUNIT(dev));
1611 struct fd_type *type = fd->sc_type;
1612 struct buf *bp;
1613
1614 /* set up a buffer header for fdstrategy() */
1615 bp = getiobuf(NULL, false);
1616 if (bp == NULL)
1617 return ENOBUFS;
1618
1619 bp->b_cflags = BC_BUSY;
1620 bp->b_flags = B_PHYS | B_FORMAT;
1621 bp->b_proc = l->l_proc;
1622 bp->b_dev = dev;
1623
1624 /*
1625 * calculate a fake blkno, so fdstrategy() would initiate a
1626 * seek to the requested cylinder
1627 */
1628 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1629 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1630
1631 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1632 bp->b_data = (void *)finfo;
1633
1634 #ifdef DEBUG
1635 printf("fdformat: blkno %" PRIx64 " count %x\n",
1636 bp->b_blkno, bp->b_bcount);
1637 #endif
1638
1639 /* now do the format */
1640 fdstrategy(bp);
1641
1642 /* ...and wait for it to complete */
1643 rv = biowait(bp);
1644 putiobuf(bp);
1645 return rv;
1646 }
1647
1648 /*
1649 * Mountroot hook: prompt the user to enter the root file system
1650 * floppy.
1651 */
1652 void
1653 fd_mountroot_hook(device_t dev)
1654 {
1655 int c;
1656
1657 printf("Insert filesystem floppy and press return.");
1658 cnpollc(1);
1659 for (;;) {
1660 c = cngetc();
1661 if ((c == '\r') || (c == '\n')) {
1662 printf("\n");
1663 break;
1664 }
1665 }
1666 cnpollc(0);
1667 }
1668
1669 static void
1670 fd_set_properties(struct fd_softc *fd)
1671 {
1672 prop_dictionary_t disk_info, odisk_info, geom;
1673 const struct fd_type *fdt;
1674 int secsize;
1675
1676 fdt = fd->sc_type;
1677 if (fdt == NULL) {
1678 fdt = fd->sc_deftype;
1679 if (fdt == NULL)
1680 return;
1681 }
1682
1683 disk_info = prop_dictionary_create();
1684
1685 geom = prop_dictionary_create();
1686
1687 prop_dictionary_set_uint64(geom, "sectors-per-unit",
1688 fdt->size);
1689
1690 switch (fdt->secsize) {
1691 case 2:
1692 secsize = 512;
1693 break;
1694 case 3:
1695 secsize = 1024;
1696 break;
1697 default:
1698 secsize = 0;
1699 }
1700
1701 prop_dictionary_set_uint32(geom, "sector-size",
1702 secsize);
1703
1704 prop_dictionary_set_uint16(geom, "sectors-per-track",
1705 fdt->sectrac);
1706
1707 prop_dictionary_set_uint16(geom, "tracks-per-cylinder",
1708 fdt->heads);
1709
1710 prop_dictionary_set_uint64(geom, "cylinders-per-unit",
1711 fdt->cyls);
1712
1713 prop_dictionary_set(disk_info, "geometry", geom);
1714 prop_object_release(geom);
1715
1716 prop_dictionary_set(device_properties(fd->sc_dev),
1717 "disk-info", disk_info);
1718
1719 /*
1720 * Don't release disk_info here; we keep a reference to it.
1721 * disk_detach() will release it when we go away.
1722 */
1723
1724 odisk_info = fd->sc_dk.dk_info;
1725 fd->sc_dk.dk_info = disk_info;
1726 if (odisk_info)
1727 prop_object_release(odisk_info);
1728 }
1729