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