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