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