fd.c revision 1.81 1 /* $NetBSD: fd.c,v 1.81 2008/02/22 23:40:49 dyoung 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.81 2008/02/22 23:40:49 dyoung 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(fdisa, sizeof(struct fd_softc),
222 fdprobe, fdattach, fddetach, NULL);
223 #else
224 CFATTACH_DECL(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(&fdc->sc_dev, (void *)&fa, fdprint);
460 }
461 }
462 fdc->sc_state = DEVIDLE;
463 }
464
465 int
466 fdprobe(device_t parent, struct cfdata *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 callout_init(&fd->sc_motoron_ch, 0);
551 callout_init(&fd->sc_motoroff_ch, 0);
552
553 /* XXX Allow `flags' to override device type? */
554
555 if (type)
556 printf(": %s, %d cyl, %d head, %d sec\n", type->name,
557 type->cyls, type->heads, type->sectrac);
558 else
559 printf(": density unknown\n");
560
561 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
562 fd->sc_cylin = -1;
563 fd->sc_drive = drive;
564 fd->sc_deftype = type;
565 fdc->sc_fd[drive] = fd;
566
567 /*
568 * Initialize and attach the disk structure.
569 */
570 disk_init(&fd->sc_dk, device_xname(&fd->sc_dev), &fddkdriver);
571 disk_attach(&fd->sc_dk);
572
573 /*
574 * Establish a mountroot hook.
575 */
576 fd->sc_roothook =
577 mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
578
579 #if NRND > 0
580 rnd_attach_source(&fd->rnd_source, device_xname(&fd->sc_dev),
581 RND_TYPE_DISK, 0);
582 #endif
583
584 fd_set_properties(fd);
585
586 if (!pmf_device_register(self, NULL, NULL))
587 aprint_error_dev(self, "cannot set power mgmt handler\n");
588 }
589
590 static int
591 fddetach(device_t self, int flags)
592 {
593 struct fd_softc *fd = device_private(self);
594 int bmaj, cmaj, i, mn;
595
596 fd_motor_off(fd);
597
598 /* locate the major number */
599 bmaj = bdevsw_lookup_major(&fd_bdevsw);
600 cmaj = cdevsw_lookup_major(&fd_cdevsw);
601
602 /* Nuke the vnodes for any open instances. */
603 for (i = 0; i < MAXPARTITIONS; i++) {
604 mn = DISKMINOR(device_unit(self), i);
605 vdevgone(bmaj, mn, mn, VBLK);
606 vdevgone(cmaj, mn, mn, VCHR);
607 }
608
609 pmf_device_deregister(self);
610
611 #if 0 /* XXX need to undo at detach? */
612 fd_set_properties(fd);
613 #endif
614 #if NRND > 0
615 rnd_detach_source(&fd->rnd_source);
616 #endif
617
618 disk_detach(&fd->sc_dk);
619
620 /* Kill off any queued buffers. */
621 bufq_drain(fd->sc_q);
622
623 bufq_free(fd->sc_q);
624
625 callout_destroy(&fd->sc_motoroff_ch);
626 callout_destroy(&fd->sc_motoron_ch);
627
628 return 0;
629 }
630
631 #if defined(i386)
632 /*
633 * Translate nvram type into internal data structure. Return NULL for
634 * none/unknown/unusable.
635 */
636 const struct fd_type *
637 fd_nvtotype(const char *fdc, int nvraminfo, int drive)
638 {
639 int type;
640
641 type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
642 switch (type) {
643 case NVRAM_DISKETTE_NONE:
644 return NULL;
645 case NVRAM_DISKETTE_12M:
646 return &fd_types[1];
647 case NVRAM_DISKETTE_TYPE5:
648 case NVRAM_DISKETTE_TYPE6:
649 /* XXX We really ought to handle 2.88MB format. */
650 case NVRAM_DISKETTE_144M:
651 #if NMCA > 0
652 if (MCA_system)
653 return &mca_fd_types[0];
654 else
655 #endif /* NMCA > 0 */
656 return &fd_types[0];
657 case NVRAM_DISKETTE_360K:
658 return &fd_types[3];
659 case NVRAM_DISKETTE_720K:
660 #if NMCA > 0
661 if (MCA_system)
662 return &mca_fd_types[1];
663 else
664 #endif /* NMCA > 0 */
665 return &fd_types[4];
666 default:
667 printf("%s: drive %d: unknown device type 0x%x\n",
668 fdc, drive, type);
669 return NULL;
670 }
671 }
672 #endif /* i386 */
673
674 static const struct fd_type *
675 fd_dev_to_type(struct fd_softc *fd, dev_t dev)
676 {
677 u_int type = FDTYPE(dev);
678
679 if (type > __arraycount(fd_types))
680 return NULL;
681 return type ? &fd_types[type - 1] : fd->sc_deftype;
682 }
683
684 void
685 fdstrategy(struct buf *bp)
686 {
687 struct fd_softc *fd = device_lookup(&fd_cd, FDUNIT(bp->b_dev));
688 struct fdc_softc *fdc = device_private(device_parent(&fd->sc_dev));
689 int sz;
690
691 /* Valid unit, controller, and request? */
692 if (bp->b_blkno < 0 ||
693 ((bp->b_bcount % FDC_BSIZE) != 0 &&
694 (bp->b_flags & B_FORMAT) == 0)) {
695 bp->b_error = EINVAL;
696 goto done;
697 }
698
699 /* If it's a null transfer, return immediately. */
700 if (bp->b_bcount == 0)
701 goto done;
702
703 sz = howmany(bp->b_bcount, FDC_BSIZE);
704
705 if (bp->b_blkno + sz > fd->sc_type->size) {
706 sz = fd->sc_type->size - bp->b_blkno;
707 if (sz == 0) {
708 /* If exactly at end of disk, return EOF. */
709 goto done;
710 }
711 if (sz < 0) {
712 /* If past end of disk, return EINVAL. */
713 bp->b_error = EINVAL;
714 goto done;
715 }
716 /* Otherwise, truncate request. */
717 bp->b_bcount = sz << DEV_BSHIFT;
718 }
719
720 bp->b_rawblkno = bp->b_blkno;
721 bp->b_cylinder =
722 bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
723
724 #ifdef FD_DEBUG
725 printf("fdstrategy: b_blkno %llu b_bcount %d blkno %llu cylin %d "
726 "sz %d\n", (unsigned long long)bp->b_blkno, bp->b_bcount,
727 (unsigned long long)fd->sc_blkno, bp->b_cylinder, sz);
728 #endif
729
730 /* Queue transfer on drive, activate drive and controller if idle. */
731 mutex_enter(&fdc->sc_mtx);
732 BUFQ_PUT(fd->sc_q, bp);
733 callout_stop(&fd->sc_motoroff_ch); /* a good idea */
734 if (fd->sc_active == 0)
735 fdstart(fd);
736 #ifdef DIAGNOSTIC
737 else {
738 if (fdc->sc_state == DEVIDLE) {
739 printf("fdstrategy: controller inactive\n");
740 fdcstart(fdc);
741 }
742 }
743 #endif
744 mutex_exit(&fdc->sc_mtx);
745 return;
746
747 done:
748 /* Toss transfer; we're done early. */
749 bp->b_resid = bp->b_bcount;
750 biodone(bp);
751 }
752
753 void
754 fdstart(struct fd_softc *fd)
755 {
756 struct fdc_softc *fdc = device_private(device_parent(&fd->sc_dev));
757 int active = !TAILQ_EMPTY(&fdc->sc_drives);
758
759 KASSERT(mutex_owned(&fdc->sc_mtx));
760 /* Link into controller queue. */
761 fd->sc_active = 1;
762 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
763
764 /* If controller not already active, start it. */
765 if (!active)
766 fdcstart(fdc);
767 }
768
769 void
770 fdfinish(struct fd_softc *fd, struct buf *bp)
771 {
772 struct fdc_softc *fdc = device_private(device_parent(&fd->sc_dev));
773
774 /*
775 * Move this drive to the end of the queue to give others a `fair'
776 * chance. We only force a switch if N operations are completed while
777 * another drive is waiting to be serviced, since there is a long motor
778 * startup delay whenever we switch.
779 */
780 (void)BUFQ_GET(fd->sc_q);
781 if (TAILQ_NEXT(fd, sc_drivechain) && ++fd->sc_ops >= 8) {
782 fd->sc_ops = 0;
783 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
784 if (BUFQ_PEEK(fd->sc_q) != NULL)
785 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
786 else
787 fd->sc_active = 0;
788 }
789 bp->b_resid = fd->sc_bcount;
790 fd->sc_skip = 0;
791
792 #if NRND > 0
793 rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
794 #endif
795
796 biodone(bp);
797 /* turn off motor 5s from now */
798 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
799 fdc->sc_state = DEVIDLE;
800 }
801
802 int
803 fdread(dev_t dev, struct uio *uio, int flags)
804 {
805
806 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
807 }
808
809 int
810 fdwrite(dev_t dev, struct uio *uio, int flags)
811 {
812
813 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
814 }
815
816 void
817 fd_set_motor(struct fdc_softc *fdc, int reset)
818 {
819 struct fd_softc *fd;
820 u_char status;
821 int n;
822
823 if ((fd = TAILQ_FIRST(&fdc->sc_drives)) != NULL)
824 status = fd->sc_drive;
825 else
826 status = 0;
827 if (!reset)
828 status |= FDO_FRST | FDO_FDMAEN;
829 for (n = 0; n < 4; n++)
830 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
831 status |= FDO_MOEN(n);
832 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, status);
833 }
834
835 void
836 fd_motor_off(void *arg)
837 {
838 struct fd_softc *fd = arg;
839 struct fdc_softc *fdc;
840
841 fdc = device_private(device_parent(&fd->sc_dev));
842
843 mutex_enter(&fdc->sc_mtx);
844 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
845 fd_set_motor(fdc, 0);
846 mutex_exit(&fdc->sc_mtx);
847 }
848
849 void
850 fd_motor_on(void *arg)
851 {
852 struct fd_softc *fd = arg;
853 struct fdc_softc *fdc = device_private(device_parent(&fd->sc_dev));
854
855 mutex_enter(&fdc->sc_mtx);
856 fd->sc_flags &= ~FD_MOTOR_WAIT;
857 if (TAILQ_FIRST(&fdc->sc_drives) == fd && fdc->sc_state == MOTORWAIT)
858 (void)fdcintr1(fdc);
859 mutex_exit(&fdc->sc_mtx);
860 }
861
862 int
863 fdcresult(struct fdc_softc *fdc)
864 {
865 bus_space_tag_t iot = fdc->sc_iot;
866 bus_space_handle_t ioh = fdc->sc_ioh;
867 u_char i;
868 u_int j = 100000,
869 n = 0;
870
871 for (; j; j--) {
872 i = bus_space_read_1(iot, ioh, fdsts) &
873 (NE7_DIO | NE7_RQM | NE7_CB);
874 if (i == NE7_RQM)
875 return n;
876 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
877 if (n >= sizeof(fdc->sc_status)) {
878 log(LOG_ERR, "fdcresult: overrun\n");
879 return -1;
880 }
881 fdc->sc_status[n++] =
882 bus_space_read_1(iot, ioh, fddata);
883 }
884 delay(10);
885 }
886 log(LOG_ERR, "fdcresult: timeout\n");
887 return -1;
888 }
889
890 int
891 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
892 {
893 u_char i;
894 u_int j = 100000;
895
896 for (; j; j--) {
897 i = bus_space_read_1(iot, ioh, fdsts) &
898 (NE7_DIO | NE7_RQM);
899 if (i == NE7_RQM) {
900 bus_space_write_1(iot, ioh, fddata, x);
901 return 0;
902 }
903 delay(10);
904 }
905 return -1;
906 }
907
908 int
909 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
910 {
911 struct fd_softc *fd;
912 const struct fd_type *type;
913
914 fd = device_lookup(&fd_cd, FDUNIT(dev));
915 if (fd == NULL)
916 return (ENXIO);
917
918 type = fd_dev_to_type(fd, dev);
919 if (type == NULL)
920 return ENXIO;
921
922 if ((fd->sc_flags & FD_OPEN) != 0 &&
923 memcmp(fd->sc_type, type, sizeof(*type)))
924 return EBUSY;
925
926 fd->sc_type_copy = *type;
927 fd->sc_type = &fd->sc_type_copy;
928 fd->sc_cylin = -1;
929 fd->sc_flags |= FD_OPEN;
930
931 fd_set_properties(fd);
932
933 return 0;
934 }
935
936 int
937 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
938 {
939 struct fd_softc *fd = device_lookup(&fd_cd, FDUNIT(dev));
940
941 fd->sc_flags &= ~FD_OPEN;
942 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
943 return 0;
944 }
945
946 void
947 fdcstart(struct fdc_softc *fdc)
948 {
949
950 KASSERT(mutex_owned(&fdc->sc_mtx));
951
952 if (!device_is_active(&fdc->sc_dev))
953 return;
954
955 #ifdef DIAGNOSTIC
956 /* only got here if controller's drive queue was inactive; should
957 be in idle state */
958 if (fdc->sc_state != DEVIDLE) {
959 printf("fdcstart: not idle\n");
960 return;
961 }
962 #endif
963 (void)fdcintr1(fdc);
964 }
965
966 void
967 fdcstatus(device_t dv, int n, const char *s)
968 {
969 struct fdc_softc *fdc = device_private(device_parent(dv));
970 char bits[64];
971
972 if (n == 0) {
973 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
974 (void) fdcresult(fdc);
975 n = 2;
976 }
977
978 aprint_normal_dev(dv, "%s", s);
979
980 switch (n) {
981 case 0:
982 printf("\n");
983 break;
984 case 2:
985 printf(" (st0 %s cyl %d)\n",
986 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
987 bits, sizeof(bits)), fdc->sc_status[1]);
988 break;
989 case 7:
990 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
991 NE7_ST0BITS, bits, sizeof(bits)));
992 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
993 NE7_ST1BITS, bits, sizeof(bits)));
994 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
995 NE7_ST2BITS, bits, sizeof(bits)));
996 printf(" cyl %d head %d sec %d)\n",
997 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
998 break;
999 #ifdef DIAGNOSTIC
1000 default:
1001 printf("\nfdcstatus: weird size");
1002 break;
1003 #endif
1004 }
1005 }
1006
1007 void
1008 fdctimeout(void *arg)
1009 {
1010 struct fdc_softc *fdc = arg;
1011 struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives);
1012
1013 mutex_enter(&fdc->sc_mtx);
1014 #ifdef DEBUG
1015 log(LOG_ERR, "fdctimeout: state %d\n", fdc->sc_state);
1016 #endif
1017 fdcstatus(&fd->sc_dev, 0, "timeout");
1018
1019 if (BUFQ_PEEK(fd->sc_q) != NULL)
1020 fdc->sc_state++;
1021 else
1022 fdc->sc_state = DEVIDLE;
1023
1024 (void)fdcintr1(fdc);
1025 mutex_exit(&fdc->sc_mtx);
1026 }
1027
1028 static int
1029 fdcintr1(struct fdc_softc *fdc)
1030 {
1031 #define st0 fdc->sc_status[0]
1032 #define cyl fdc->sc_status[1]
1033 struct fd_softc *fd;
1034 struct buf *bp;
1035 bus_space_tag_t iot = fdc->sc_iot;
1036 bus_space_handle_t ioh = fdc->sc_ioh;
1037 int read, head, sec, i, nblks;
1038 struct fd_type *type;
1039 struct ne7_fd_formb *finfo = NULL;
1040
1041 KASSERT(mutex_owned(&fdc->sc_mtx));
1042 if (fdc->sc_state == PROBING) {
1043 #ifdef DEBUG
1044 printf("fdcintr: got probe interrupt\n");
1045 #endif
1046 fdc->sc_probe++;
1047 goto out;
1048 }
1049
1050 loop:
1051 /* Is there a drive for the controller to do a transfer with? */
1052 fd = TAILQ_FIRST(&fdc->sc_drives);
1053 if (fd == NULL) {
1054 fdc->sc_state = DEVIDLE;
1055 goto out;
1056 }
1057
1058 /* Is there a transfer to this drive? If not, deactivate drive. */
1059 bp = BUFQ_PEEK(fd->sc_q);
1060 if (bp == NULL) {
1061 fd->sc_ops = 0;
1062 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1063 fd->sc_active = 0;
1064 goto loop;
1065 }
1066
1067 if (bp->b_flags & B_FORMAT)
1068 finfo = (struct ne7_fd_formb *)bp->b_data;
1069
1070 switch (fdc->sc_state) {
1071 case DEVIDLE:
1072 fdc->sc_errors = 0;
1073 fd->sc_skip = 0;
1074 fd->sc_bcount = bp->b_bcount;
1075 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1076 callout_stop(&fd->sc_motoroff_ch);
1077 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1078 fdc->sc_state = MOTORWAIT;
1079 return 1;
1080 }
1081 if ((fd->sc_flags & FD_MOTOR) == 0) {
1082 /* Turn on the motor, being careful about pairing. */
1083 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
1084 if (ofd && ofd->sc_flags & FD_MOTOR) {
1085 callout_stop(&ofd->sc_motoroff_ch);
1086 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1087 }
1088 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1089 fd_set_motor(fdc, 0);
1090 fdc->sc_state = MOTORWAIT;
1091 /* Allow .25s for motor to stabilize. */
1092 callout_reset(&fd->sc_motoron_ch, hz / 4,
1093 fd_motor_on, fd);
1094 return 1;
1095 }
1096 /* Make sure the right drive is selected. */
1097 fd_set_motor(fdc, 0);
1098
1099 /* fall through */
1100 case DOSEEK:
1101 doseek:
1102 if (fd->sc_cylin == bp->b_cylinder)
1103 goto doio;
1104
1105 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1106 out_fdc(iot, ioh, fd->sc_type->steprate);
1107 out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */
1108
1109 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1110 out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1111 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1112
1113 fd->sc_cylin = -1;
1114 fdc->sc_state = SEEKWAIT;
1115
1116 iostat_seek(fd->sc_dk.dk_stats);
1117 disk_busy(&fd->sc_dk);
1118
1119 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1120 return 1;
1121
1122 case DOIO:
1123 doio:
1124 type = fd->sc_type;
1125 if (finfo)
1126 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1127 (char *)finfo;
1128 sec = fd->sc_blkno % type->seccyl;
1129 nblks = type->seccyl - sec;
1130 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1131 nblks = min(nblks, fdc->sc_maxiosize / FDC_BSIZE);
1132 fd->sc_nblks = nblks;
1133 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
1134 head = sec / type->sectrac;
1135 sec -= head * type->sectrac;
1136 #ifdef DIAGNOSTIC
1137 {
1138 int block;
1139 block = (fd->sc_cylin * type->heads + head)
1140 * type->sectrac + sec;
1141 if (block != fd->sc_blkno) {
1142 printf("fdcintr: block %d != blkno "
1143 "%" PRId64 "\n", block, fd->sc_blkno);
1144 #ifdef DDB
1145 Debugger();
1146 #endif
1147 }
1148 }
1149 #endif
1150 read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE;
1151 isa_dmastart(fdc->sc_ic, fdc->sc_drq,
1152 (char *)bp->b_data + fd->sc_skip, fd->sc_nbytes,
1153 NULL, read | DMAMODE_DEMAND, BUS_DMA_NOWAIT);
1154 bus_space_write_1(iot, fdc->sc_fdctlioh, 0, type->rate);
1155 #ifdef FD_DEBUG
1156 printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1157 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1158 head, sec, nblks);
1159 #endif
1160 if (finfo) {
1161 /* formatting */
1162 if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
1163 fdc->sc_errors = 4;
1164 fdcretry(fdc);
1165 goto loop;
1166 }
1167 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1168 out_fdc(iot, ioh, finfo->fd_formb_secshift);
1169 out_fdc(iot, ioh, finfo->fd_formb_nsecs);
1170 out_fdc(iot, ioh, finfo->fd_formb_gaplen);
1171 out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
1172 } else {
1173 if (read)
1174 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1175 else
1176 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1177 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1178 out_fdc(iot, ioh, fd->sc_cylin); /* track */
1179 out_fdc(iot, ioh, head);
1180 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1181 out_fdc(iot, ioh, type->secsize);/* sector size */
1182 out_fdc(iot, ioh, type->sectrac);/* sectors/track */
1183 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1184 out_fdc(iot, ioh, type->datalen);/* data length */
1185 }
1186 fdc->sc_state = IOCOMPLETE;
1187
1188 disk_busy(&fd->sc_dk);
1189
1190 /* allow 2 seconds for operation */
1191 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1192 return 1; /* will return later */
1193
1194 case SEEKWAIT:
1195 callout_stop(&fdc->sc_timo_ch);
1196 fdc->sc_state = SEEKCOMPLETE;
1197 /* allow 1/50 second for heads to settle */
1198 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcintrcb, fdc);
1199 return 1;
1200
1201 case SEEKCOMPLETE:
1202 /* no data on seek */
1203 disk_unbusy(&fd->sc_dk, 0, 0);
1204
1205 /* Make sure seek really happened. */
1206 out_fdc(iot, ioh, NE7CMD_SENSEI);
1207 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1208 cyl != bp->b_cylinder * fd->sc_type->step) {
1209 #ifdef FD_DEBUG
1210 fdcstatus(&fd->sc_dev, 2, "seek failed");
1211 #endif
1212 fdcretry(fdc);
1213 goto loop;
1214 }
1215 fd->sc_cylin = bp->b_cylinder;
1216 goto doio;
1217
1218 case IOTIMEDOUT:
1219 isa_dmaabort(fdc->sc_ic, fdc->sc_drq);
1220 case SEEKTIMEDOUT:
1221 case RECALTIMEDOUT:
1222 case RESETTIMEDOUT:
1223 fdcretry(fdc);
1224 goto loop;
1225
1226 case IOCOMPLETE: /* IO DONE, post-analyze */
1227 callout_stop(&fdc->sc_timo_ch);
1228
1229 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
1230 (bp->b_flags & B_READ));
1231
1232 if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
1233 isa_dmaabort(fdc->sc_ic, fdc->sc_drq);
1234 #ifdef FD_DEBUG
1235 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1236 "read failed" : "write failed");
1237 printf("blkno %llu nblks %d\n",
1238 (unsigned long long)fd->sc_blkno, fd->sc_nblks);
1239 #endif
1240 fdcretry(fdc);
1241 goto loop;
1242 }
1243 isa_dmadone(fdc->sc_ic, fdc->sc_drq);
1244 if (fdc->sc_errors) {
1245 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1246 fd->sc_skip / FDC_BSIZE, NULL);
1247 printf("\n");
1248 fdc->sc_errors = 0;
1249 }
1250 fd->sc_blkno += fd->sc_nblks;
1251 fd->sc_skip += fd->sc_nbytes;
1252 fd->sc_bcount -= fd->sc_nbytes;
1253 if (!finfo && fd->sc_bcount > 0) {
1254 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1255 goto doseek;
1256 }
1257 fdfinish(fd, bp);
1258 goto loop;
1259
1260 case DORESET:
1261 /* try a reset, keep motor on */
1262 fd_set_motor(fdc, 1);
1263 delay(100);
1264 fd_set_motor(fdc, 0);
1265 fdc->sc_state = RESETCOMPLETE;
1266 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1267 return 1; /* will return later */
1268
1269 case RESETCOMPLETE:
1270 callout_stop(&fdc->sc_timo_ch);
1271 /* clear the controller output buffer */
1272 for (i = 0; i < 4; i++) {
1273 out_fdc(iot, ioh, NE7CMD_SENSEI);
1274 (void) fdcresult(fdc);
1275 }
1276
1277 /* fall through */
1278 case DORECAL:
1279 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1280 out_fdc(iot, ioh, fd->sc_drive);
1281 fdc->sc_state = RECALWAIT;
1282 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1283 return 1; /* will return later */
1284
1285 case RECALWAIT:
1286 callout_stop(&fdc->sc_timo_ch);
1287 fdc->sc_state = RECALCOMPLETE;
1288 /* allow 1/30 second for heads to settle */
1289 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcintrcb, fdc);
1290 return 1; /* will return later */
1291
1292 case RECALCOMPLETE:
1293 out_fdc(iot, ioh, NE7CMD_SENSEI);
1294 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1295 #ifdef FD_DEBUG
1296 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1297 #endif
1298 fdcretry(fdc);
1299 goto loop;
1300 }
1301 fd->sc_cylin = 0;
1302 goto doseek;
1303
1304 case MOTORWAIT:
1305 if (fd->sc_flags & FD_MOTOR_WAIT)
1306 return 1; /* time's not up yet */
1307 goto doseek;
1308
1309 default:
1310 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1311 return 1;
1312 }
1313 #undef st0
1314 #undef cyl
1315
1316 out:
1317 cv_signal(&fdc->sc_cv);
1318 return 1;
1319 }
1320
1321 static void
1322 fdcintrcb(void *arg)
1323 {
1324 (void)fdcintr(arg);
1325 }
1326
1327 int
1328 fdcintr(void *arg)
1329 {
1330 int rc;
1331 struct fdc_softc *fdc = arg;
1332
1333 mutex_enter(&fdc->sc_mtx);
1334 rc = fdcintr1(fdc);
1335 mutex_exit(&fdc->sc_mtx);
1336 return rc;
1337 }
1338
1339 void
1340 fdcretry(struct fdc_softc *fdc)
1341 {
1342 char bits[64];
1343 struct fd_softc *fd;
1344 struct buf *bp;
1345
1346 fd = TAILQ_FIRST(&fdc->sc_drives);
1347 bp = BUFQ_PEEK(fd->sc_q);
1348
1349 if (fd->sc_opts & FDOPT_NORETRY)
1350 goto fail;
1351 switch (fdc->sc_errors) {
1352 case 0:
1353 /* try again */
1354 fdc->sc_state = DOSEEK;
1355 break;
1356
1357 case 1: case 2: case 3:
1358 /* didn't work; try recalibrating */
1359 fdc->sc_state = DORECAL;
1360 break;
1361
1362 case 4:
1363 /* still no go; reset the bastard */
1364 fdc->sc_state = DORESET;
1365 break;
1366
1367 default:
1368 fail:
1369 if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1370 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1371 fd->sc_skip / FDC_BSIZE, NULL);
1372
1373 printf(" (st0 %s",
1374 bitmask_snprintf(fdc->sc_status[0],
1375 NE7_ST0BITS, bits,
1376 sizeof(bits)));
1377 printf(" st1 %s",
1378 bitmask_snprintf(fdc->sc_status[1],
1379 NE7_ST1BITS, bits,
1380 sizeof(bits)));
1381 printf(" st2 %s",
1382 bitmask_snprintf(fdc->sc_status[2],
1383 NE7_ST2BITS, bits,
1384 sizeof(bits)));
1385 printf(" cyl %d head %d sec %d)\n",
1386 fdc->sc_status[3],
1387 fdc->sc_status[4],
1388 fdc->sc_status[5]);
1389 }
1390
1391 bp->b_error = EIO;
1392 fdfinish(fd, bp);
1393 }
1394 fdc->sc_errors++;
1395 }
1396
1397 int
1398 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1399 {
1400 struct fd_softc *fd = device_lookup(&fd_cd, FDUNIT(dev));
1401 struct fdformat_parms *form_parms;
1402 struct fdformat_cmd *form_cmd;
1403 struct ne7_fd_formb *fd_formb;
1404 struct disklabel buffer;
1405 int error;
1406 unsigned int scratch;
1407 int il[FD_MAX_NSEC + 1];
1408 int i, j;
1409 #ifdef __HAVE_OLD_DISKLABEL
1410 struct disklabel newlabel;
1411 #endif
1412
1413 switch (cmd) {
1414 case DIOCGDINFO:
1415 #ifdef __HAVE_OLD_DISKLABEL
1416 case ODIOCGDINFO:
1417 #endif
1418 memset(&buffer, 0, sizeof(buffer));
1419
1420 buffer.d_secpercyl = fd->sc_type->seccyl;
1421 buffer.d_type = DTYPE_FLOPPY;
1422 buffer.d_secsize = FDC_BSIZE;
1423
1424 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1425 return EINVAL;
1426
1427 #ifdef __HAVE_OLD_DISKLABEL
1428 if (cmd == ODIOCGDINFO) {
1429 if (buffer.d_npartitions > OLDMAXPARTITIONS)
1430 return ENOTTY;
1431 memcpy(addr, &buffer, sizeof (struct olddisklabel));
1432 } else
1433 #endif
1434 *(struct disklabel *)addr = buffer;
1435 return 0;
1436
1437 case DIOCWLABEL:
1438 if ((flag & FWRITE) == 0)
1439 return EBADF;
1440 /* XXX do something */
1441 return 0;
1442
1443 case DIOCWDINFO:
1444 #ifdef __HAVE_OLD_DISKLABEL
1445 case ODIOCWDINFO:
1446 #endif
1447 {
1448 struct disklabel *lp;
1449
1450 if ((flag & FWRITE) == 0)
1451 return EBADF;
1452 #ifdef __HAVE_OLD_DISKLABEL
1453 if (cmd == ODIOCWDINFO) {
1454 memset(&newlabel, 0, sizeof newlabel);
1455 memcpy(&newlabel, addr, sizeof (struct olddisklabel));
1456 lp = &newlabel;
1457 } else
1458 #endif
1459 lp = (struct disklabel *)addr;
1460
1461 error = setdisklabel(&buffer, lp, 0, NULL);
1462 if (error)
1463 return error;
1464
1465 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1466 return error;
1467 }
1468
1469 case FDIOCGETFORMAT:
1470 form_parms = (struct fdformat_parms *)addr;
1471 form_parms->fdformat_version = FDFORMAT_VERSION;
1472 form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1473 form_parms->ncyl = fd->sc_type->cyls;
1474 form_parms->nspt = fd->sc_type->sectrac;
1475 form_parms->ntrk = fd->sc_type->heads;
1476 form_parms->stepspercyl = fd->sc_type->step;
1477 form_parms->gaplen = fd->sc_type->gap2;
1478 form_parms->fillbyte = fd->sc_type->fillbyte;
1479 form_parms->interleave = fd->sc_type->interleave;
1480 switch (fd->sc_type->rate) {
1481 case FDC_500KBPS:
1482 form_parms->xfer_rate = 500 * 1024;
1483 break;
1484 case FDC_300KBPS:
1485 form_parms->xfer_rate = 300 * 1024;
1486 break;
1487 case FDC_250KBPS:
1488 form_parms->xfer_rate = 250 * 1024;
1489 break;
1490 default:
1491 return EINVAL;
1492 }
1493 return 0;
1494
1495 case FDIOCSETFORMAT:
1496 if((flag & FWRITE) == 0)
1497 return EBADF; /* must be opened for writing */
1498 form_parms = (struct fdformat_parms *)addr;
1499 if (form_parms->fdformat_version != FDFORMAT_VERSION)
1500 return EINVAL; /* wrong version of formatting prog */
1501
1502 scratch = form_parms->nbps >> 7;
1503 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1504 scratch & ~(1 << (ffs(scratch)-1)))
1505 /* not a power-of-two multiple of 128 */
1506 return EINVAL;
1507
1508 switch (form_parms->xfer_rate) {
1509 case 500 * 1024:
1510 fd->sc_type->rate = FDC_500KBPS;
1511 break;
1512 case 300 * 1024:
1513 fd->sc_type->rate = FDC_300KBPS;
1514 break;
1515 case 250 * 1024:
1516 fd->sc_type->rate = FDC_250KBPS;
1517 break;
1518 default:
1519 return EINVAL;
1520 }
1521
1522 if (form_parms->nspt > FD_MAX_NSEC ||
1523 form_parms->fillbyte > 0xff ||
1524 form_parms->interleave > 0xff)
1525 return EINVAL;
1526 fd->sc_type->sectrac = form_parms->nspt;
1527 if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1528 return EINVAL;
1529 fd->sc_type->heads = form_parms->ntrk;
1530 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1531 fd->sc_type->secsize = ffs(scratch)-1;
1532 fd->sc_type->gap2 = form_parms->gaplen;
1533 fd->sc_type->cyls = form_parms->ncyl;
1534 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1535 form_parms->nbps / DEV_BSIZE;
1536 fd->sc_type->step = form_parms->stepspercyl;
1537 fd->sc_type->fillbyte = form_parms->fillbyte;
1538 fd->sc_type->interleave = form_parms->interleave;
1539 return 0;
1540
1541 case FDIOCFORMAT_TRACK:
1542 if((flag & FWRITE) == 0)
1543 return EBADF; /* must be opened for writing */
1544 form_cmd = (struct fdformat_cmd *)addr;
1545 if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1546 return EINVAL; /* wrong version of formatting prog */
1547
1548 if (form_cmd->head >= fd->sc_type->heads ||
1549 form_cmd->cylinder >= fd->sc_type->cyls) {
1550 return EINVAL;
1551 }
1552
1553 fd_formb = malloc(sizeof(struct ne7_fd_formb),
1554 M_TEMP, M_NOWAIT);
1555 if (fd_formb == 0)
1556 return ENOMEM;
1557
1558 fd_formb->head = form_cmd->head;
1559 fd_formb->cyl = form_cmd->cylinder;
1560 fd_formb->transfer_rate = fd->sc_type->rate;
1561 fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1562 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1563 fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1564 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1565
1566 memset(il, 0, sizeof il);
1567 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1568 while (il[(j%fd_formb->fd_formb_nsecs)+1])
1569 j++;
1570 il[(j%fd_formb->fd_formb_nsecs)+1] = i;
1571 j += fd->sc_type->interleave;
1572 }
1573 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1574 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1575 fd_formb->fd_formb_headno(i) = form_cmd->head;
1576 fd_formb->fd_formb_secno(i) = il[i+1];
1577 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1578 }
1579
1580 error = fdformat(dev, fd_formb, l);
1581 free(fd_formb, M_TEMP);
1582 return error;
1583
1584 case FDIOCGETOPTS: /* get drive options */
1585 *(int *)addr = fd->sc_opts;
1586 return 0;
1587
1588 case FDIOCSETOPTS: /* set drive options */
1589 fd->sc_opts = *(int *)addr;
1590 return 0;
1591
1592 default:
1593 return ENOTTY;
1594 }
1595
1596 #ifdef DIAGNOSTIC
1597 panic("fdioctl: impossible");
1598 #endif
1599 }
1600
1601 int
1602 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l)
1603 {
1604 int rv = 0;
1605 struct fd_softc *fd = device_lookup(&fd_cd, FDUNIT(dev));
1606 struct fd_type *type = fd->sc_type;
1607 struct buf *bp;
1608
1609 /* set up a buffer header for fdstrategy() */
1610 bp = getiobuf(NULL, false);
1611 if (bp == NULL)
1612 return ENOBUFS;
1613
1614 bp->b_cflags = BC_BUSY;
1615 bp->b_flags = B_PHYS | B_FORMAT;
1616 bp->b_proc = l->l_proc;
1617 bp->b_dev = dev;
1618
1619 /*
1620 * calculate a fake blkno, so fdstrategy() would initiate a
1621 * seek to the requested cylinder
1622 */
1623 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1624 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1625
1626 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1627 bp->b_data = (void *)finfo;
1628
1629 #ifdef DEBUG
1630 printf("fdformat: blkno %" PRIx64 " count %x\n",
1631 bp->b_blkno, bp->b_bcount);
1632 #endif
1633
1634 /* now do the format */
1635 fdstrategy(bp);
1636
1637 /* ...and wait for it to complete */
1638 rv = biowait(bp);
1639 putiobuf(bp);
1640 return rv;
1641 }
1642
1643 /*
1644 * Mountroot hook: prompt the user to enter the root file system
1645 * floppy.
1646 */
1647 void
1648 fd_mountroot_hook(device_t dev)
1649 {
1650 int c;
1651
1652 printf("Insert filesystem floppy and press return.");
1653 cnpollc(1);
1654 for (;;) {
1655 c = cngetc();
1656 if ((c == '\r') || (c == '\n')) {
1657 printf("\n");
1658 break;
1659 }
1660 }
1661 cnpollc(0);
1662 }
1663
1664 static void
1665 fd_set_properties(struct fd_softc *fd)
1666 {
1667 prop_dictionary_t disk_info, odisk_info, geom;
1668 const struct fd_type *fdt;
1669 int secsize;
1670
1671 fdt = fd->sc_type;
1672 if (fdt == NULL) {
1673 fdt = fd->sc_deftype;
1674 if (fdt == NULL)
1675 return;
1676 }
1677
1678 disk_info = prop_dictionary_create();
1679
1680 geom = prop_dictionary_create();
1681
1682 prop_dictionary_set_uint64(geom, "sectors-per-unit",
1683 fdt->size);
1684
1685 switch (fdt->secsize) {
1686 case 2:
1687 secsize = 512;
1688 break;
1689 case 3:
1690 secsize = 1024;
1691 break;
1692 default:
1693 secsize = 0;
1694 }
1695
1696 prop_dictionary_set_uint32(geom, "sector-size",
1697 secsize);
1698
1699 prop_dictionary_set_uint16(geom, "sectors-per-track",
1700 fdt->sectrac);
1701
1702 prop_dictionary_set_uint16(geom, "tracks-per-cylinder",
1703 fdt->heads);
1704
1705 prop_dictionary_set_uint64(geom, "cylinders-per-unit",
1706 fdt->cyls);
1707
1708 prop_dictionary_set(disk_info, "geometry", geom);
1709 prop_object_release(geom);
1710
1711 prop_dictionary_set(device_properties(&fd->sc_dev),
1712 "disk-info", disk_info);
1713
1714 /*
1715 * Don't release disk_info here; we keep a reference to it.
1716 * disk_detach() will release it when we go away.
1717 */
1718
1719 odisk_info = fd->sc_dk.dk_info;
1720 fd->sc_dk.dk_info = disk_info;
1721 if (odisk_info)
1722 prop_object_release(odisk_info);
1723 }
1724