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