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