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