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