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