hdfd.c revision 1.58 1 /* $NetBSD: hdfd.c,v 1.58 2007/10/08 16:41:06 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.58 2007/10/08 16:41:06 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 disk_init(&fd->sc_dk, fd->sc_dev.dv_xname, &fddkdriver);
549 disk_attach(&fd->sc_dk);
550
551 /* Needed to power off if the motor is on when we halt. */
552 fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
553 }
554
555 /*
556 * This is called from the assembly part of the interrupt handler
557 * when it is clear that the interrupt was not related to shoving
558 * data.
559 */
560 void
561 fdc_ctrl_intr(frame)
562 struct clockframe frame;
563 {
564 int s;
565
566 /*
567 * Disable further interrupts. The fdcintr() routine
568 * explicitly enables them when needed.
569 */
570 MFP2->mf_ierb &= ~IB_DCHG;
571
572 /*
573 * Set fddmalen to zero so no pseudo-DMA transfers will
574 * occur.
575 */
576 fddmalen = 0;
577
578 if (!BASEPRI(frame.cf_sr)) {
579 /*
580 * We don't want to stay on ipl6.....
581 */
582 add_sicallback((si_farg)fdcpseudointr, intr_arg, 0);
583 }
584 else {
585 s = splbio();
586 (void) fdcintr(intr_arg);
587 splx(s);
588 }
589 }
590
591 inline struct fd_type *
592 fd_dev_to_type(fd, dev)
593 struct fd_softc *fd;
594 dev_t dev;
595 {
596 int type = FDTYPE(dev);
597
598 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
599 return NULL;
600 return type ? &fd_types[type - 1] : fd->sc_deftype;
601 }
602
603 void
604 fdstrategy(bp)
605 register struct buf *bp; /* IO operation to perform */
606 {
607 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(bp->b_dev)];
608 int sz;
609 int s;
610
611 /* Valid unit, controller, and request? */
612 if (bp->b_blkno < 0 ||
613 ((bp->b_bcount % FDC_BSIZE) != 0 &&
614 (bp->b_flags & B_FORMAT) == 0)) {
615 bp->b_error = EINVAL;
616 goto done;
617 }
618
619 /* If it's a null transfer, return immediately. */
620 if (bp->b_bcount == 0)
621 goto done;
622
623 sz = howmany(bp->b_bcount, FDC_BSIZE);
624
625 if (bp->b_blkno + sz > fd->sc_type->size) {
626 sz = fd->sc_type->size - bp->b_blkno;
627 if (sz == 0) {
628 /* If exactly at end of disk, return EOF. */
629 goto done;
630 }
631 if (sz < 0) {
632 /* If past end of disk, return EINVAL. */
633 bp->b_error = EINVAL;
634 goto done;
635 }
636 /* Otherwise, truncate request. */
637 bp->b_bcount = sz << DEV_BSHIFT;
638 }
639
640 bp->b_rawblkno = bp->b_blkno;
641 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl;
642
643 #ifdef FD_DEBUG
644 printf("fdstrategy: b_blkno %d b_bcount %ld blkno %qd cylin %ld sz"
645 " %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno,
646 bp->b_cylinder, sz);
647 #endif
648
649 /* Queue transfer on drive, activate drive and controller if idle. */
650 s = splbio();
651 BUFQ_PUT(fd->sc_q, bp);
652 callout_stop(&fd->sc_motoroff_ch); /* a good idea */
653 if (fd->sc_active == 0)
654 fdstart(fd);
655 #ifdef DIAGNOSTIC
656 else {
657 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
658 if (fdc->sc_state == DEVIDLE) {
659 printf("fdstrategy: controller inactive\n");
660 fdcstart(fdc);
661 }
662 }
663 #endif
664 splx(s);
665 return;
666
667 done:
668 /* Toss transfer; we're done early. */
669 bp->b_resid = bp->b_bcount;
670 biodone(bp);
671 }
672
673 void
674 fdstart(fd)
675 struct fd_softc *fd;
676 {
677 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
678 int active = fdc->sc_drives.tqh_first != 0;
679
680 /* Link into controller queue. */
681 fd->sc_active = 1;
682 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
683
684 /* If controller not already active, start it. */
685 if (!active)
686 fdcstart(fdc);
687 }
688
689 void
690 fdfinish(fd, bp)
691 struct fd_softc *fd;
692 struct buf *bp;
693 {
694 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
695
696 /*
697 * Move this drive to the end of the queue to give others a `fair'
698 * chance. We only force a switch if N operations are completed while
699 * another drive is waiting to be serviced, since there is a long motor
700 * startup delay whenever we switch.
701 */
702 (void)BUFQ_GET(fd->sc_q);
703 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
704 fd->sc_ops = 0;
705 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
706 if (BUFQ_PEEK(fd->sc_q) != NULL)
707 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
708 else
709 fd->sc_active = 0;
710 }
711 bp->b_resid = fd->sc_bcount;
712 fd->sc_skip = 0;
713
714 biodone(bp);
715 /* turn off motor 5s from now */
716 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
717 fdc->sc_state = DEVIDLE;
718 }
719
720 int
721 fdread(dev, uio, flags)
722 dev_t dev;
723 struct uio *uio;
724 int flags;
725 {
726 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
727 }
728
729 int
730 fdwrite(dev, uio, flags)
731 dev_t dev;
732 struct uio *uio;
733 int flags;
734 {
735 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
736 }
737
738 void
739 fd_set_motor(fdc, reset)
740 struct fdc_softc *fdc;
741 int reset;
742 {
743 struct fd_softc *fd;
744 u_char status;
745 int n;
746
747 if ((fd = fdc->sc_drives.tqh_first) != NULL)
748 status = fd->sc_drive;
749 else
750 status = 0;
751 if (!reset)
752 status |= FDO_FRST | FDO_FDMAEN;
753 for (n = 0; n < 4; n++)
754 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
755 status |= FDO_MOEN(n);
756 wrt_fdc_reg(fdout, status);
757 }
758
759 void
760 fd_motor_off(arg)
761 void *arg;
762 {
763 struct fd_softc *fd = arg;
764 int s;
765
766 s = splbio();
767 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
768 fd_set_motor((struct fdc_softc *) device_parent(&fd->sc_dev), 0);
769 splx(s);
770 }
771
772 void
773 fd_motor_on(arg)
774 void *arg;
775 {
776 struct fd_softc *fd = arg;
777 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
778 int s;
779
780 s = splbio();
781 fd->sc_flags &= ~FD_MOTOR_WAIT;
782 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
783 (void) fdcintr(fdc);
784 splx(s);
785 }
786
787 int
788 fdcresult(fdc)
789 struct fdc_softc *fdc;
790 {
791 u_char i;
792 int j = 100000,
793 n = 0;
794
795 for (; j; j--) {
796 i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB);
797 if (i == NE7_RQM)
798 return n;
799 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
800 if (n >= sizeof(fdc->sc_status)) {
801 log(LOG_ERR, "fdcresult: overrun\n");
802 return -1;
803 }
804 fdc->sc_status[n++] = rd_fdc_reg(fddata);
805 }
806 else delay(10);
807 }
808 log(LOG_ERR, "fdcresult: timeout\n");
809 return -1;
810 }
811
812 int
813 out_fdc(x)
814 u_char x;
815 {
816 int i = 100000;
817
818 while (((rd_fdc_reg(fdsts) & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0)
819 delay(1);
820 if (i <= 0)
821 return -1;
822 wrt_fdc_reg(fddata, x);
823 return 0;
824 }
825
826 int
827 fdopen(dev, flags, mode, l)
828 dev_t dev;
829 int flags;
830 int mode;
831 struct lwp *l;
832 {
833 int unit;
834 struct fd_softc *fd;
835 struct fd_type *type;
836
837 unit = FDUNIT(dev);
838 if (unit >= hdfd_cd.cd_ndevs)
839 return ENXIO;
840 fd = hdfd_cd.cd_devs[unit];
841 if (fd == 0)
842 return ENXIO;
843 type = fd_dev_to_type(fd, dev);
844 if (type == NULL)
845 return ENXIO;
846
847 if ((fd->sc_flags & FD_OPEN) != 0 &&
848 fd->sc_type != type)
849 return EBUSY;
850
851 fd->sc_type = type;
852 fd->sc_cylin = -1;
853 fd->sc_flags |= FD_OPEN;
854 fdgetdisklabel(fd, dev);
855
856 return 0;
857 }
858
859 int
860 fdclose(dev, flags, mode, l)
861 dev_t dev;
862 int flags;
863 int mode;
864 struct lwp *l;
865 {
866 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
867
868 fd->sc_flags &= ~(FD_OPEN|FD_HAVELAB);
869 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
870 return 0;
871 }
872
873 void
874 fdcstart(fdc)
875 struct fdc_softc *fdc;
876 {
877
878 #ifdef DIAGNOSTIC
879 /* only got here if controller's drive queue was inactive; should
880 be in idle state */
881 if (fdc->sc_state != DEVIDLE) {
882 printf("fdcstart: not idle\n");
883 return;
884 }
885 #endif
886 (void) fdcintr(fdc);
887 }
888
889 void
890 fdcstatus(dv, n, s)
891 struct device *dv;
892 int n;
893 const char *s;
894 {
895 struct fdc_softc *fdc = (void *) device_parent(dv);
896 char bits[64];
897
898 if (n == 0) {
899 out_fdc(NE7CMD_SENSEI);
900 (void) fdcresult(fdc);
901 n = 2;
902 }
903
904 printf("%s: %s", dv->dv_xname, s);
905
906 switch (n) {
907 case 0:
908 printf("\n");
909 break;
910 case 2:
911 printf(" (st0 %s cyl %d)\n",
912 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
913 bits, sizeof(bits)), fdc->sc_status[1]);
914 break;
915 case 7:
916 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
917 NE7_ST0BITS, bits, sizeof(bits)));
918 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
919 NE7_ST1BITS, bits, sizeof(bits)));
920 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
921 NE7_ST2BITS, bits, sizeof(bits)));
922 printf(" cyl %d head %d sec %d)\n",
923 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
924 break;
925 #ifdef DIAGNOSTIC
926 default:
927 printf("\nfdcstatus: weird size");
928 break;
929 #endif
930 }
931 }
932
933 void
934 fdctimeout(arg)
935 void *arg;
936 {
937 struct fdc_softc *fdc = arg;
938 struct fd_softc *fd = fdc->sc_drives.tqh_first;
939 int s;
940
941 s = splbio();
942 fdcstatus(&fd->sc_dev, 0, "timeout");
943
944 if (BUFQ_PEEK(fd->sc_q) != NULL)
945 fdc->sc_state++;
946 else
947 fdc->sc_state = DEVIDLE;
948
949 (void) fdcintr(fdc);
950 splx(s);
951 }
952
953 void
954 fdcpseudointr(arg)
955 void *arg;
956 {
957 int s;
958
959 /* Just ensure it has the right spl. */
960 s = splbio();
961 (void) fdcintr(arg);
962 splx(s);
963 }
964
965 int
966 fdcintr(arg)
967 void *arg;
968 {
969 struct fdc_softc *fdc = arg;
970 #define st0 fdc->sc_status[0]
971 #define st1 fdc->sc_status[1]
972 #define cyl fdc->sc_status[1]
973
974 struct fd_softc *fd;
975 struct buf *bp;
976 int read, head, sec, i, nblks;
977 struct fd_type *type;
978 struct ne7_fd_formb *finfo = NULL;
979
980 loop:
981 /* Is there a drive for the controller to do a transfer with? */
982 fd = fdc->sc_drives.tqh_first;
983 if (fd == NULL) {
984 fdc->sc_state = DEVIDLE;
985 return 1;
986 }
987
988 /* Is there a transfer to this drive? If not, deactivate drive. */
989 bp = BUFQ_PEEK(fd->sc_q);
990 if (bp == NULL) {
991 fd->sc_ops = 0;
992 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
993 fd->sc_active = 0;
994 goto loop;
995 }
996
997 if (bp->b_flags & B_FORMAT)
998 finfo = (struct ne7_fd_formb *)bp->b_data;
999
1000 switch (fdc->sc_state) {
1001 case DEVIDLE:
1002 fdc->sc_errors = 0;
1003 fdc->sc_overruns = 0;
1004 fd->sc_skip = 0;
1005 fd->sc_bcount = bp->b_bcount;
1006 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1007 callout_stop(&fd->sc_motoroff_ch);
1008 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1009 fdc->sc_state = MOTORWAIT;
1010 return 1;
1011 }
1012 if ((fd->sc_flags & FD_MOTOR) == 0) {
1013 /* Turn on the motor, being careful about pairing. */
1014 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
1015 if (ofd && ofd->sc_flags & FD_MOTOR) {
1016 callout_stop(&ofd->sc_motoroff_ch);
1017 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1018 }
1019 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1020 fd_set_motor(fdc, 0);
1021 fdc->sc_state = MOTORWAIT;
1022 /* Allow .25s for motor to stabilize. */
1023 callout_reset(&fd->sc_motoron_ch, hz / 4,
1024 fd_motor_on, fd);
1025 return 1;
1026 }
1027 /* Make sure the right drive is selected. */
1028 fd_set_motor(fdc, 0);
1029
1030 /* fall through */
1031 case DOSEEK:
1032 doseek:
1033 if (fd->sc_cylin == bp->b_cylinder)
1034 goto doio;
1035
1036 out_fdc(NE7CMD_SPECIFY);/* specify command */
1037 out_fdc(fd->sc_type->steprate);
1038 out_fdc(0x7); /* XXX head load time == 6ms - non-DMA */
1039
1040 fdc_ienable();
1041
1042 out_fdc(NE7CMD_SEEK); /* seek function */
1043 out_fdc(fd->sc_drive); /* drive number */
1044 out_fdc(bp->b_cylinder * fd->sc_type->step);
1045
1046 fd->sc_cylin = -1;
1047 fdc->sc_state = SEEKWAIT;
1048
1049 iostat_seek(fd->sc_dk.dk_stats);
1050 disk_busy(&fd->sc_dk);
1051
1052 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1053 return 1;
1054
1055 case DOIO:
1056 doio:
1057 if (finfo)
1058 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1059 (char *)finfo;
1060
1061 type = fd->sc_type;
1062 sec = fd->sc_blkno % type->seccyl;
1063 head = sec / type->sectrac;
1064 sec -= head * type->sectrac;
1065 nblks = type->sectrac - sec;
1066 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1067 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1068 fd->sc_nblks = nblks;
1069 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
1070 #ifdef DIAGNOSTIC
1071 {
1072 int block;
1073
1074 block = (fd->sc_cylin * type->heads + head)
1075 * type->sectrac + sec;
1076 if (block != fd->sc_blkno) {
1077 printf("fdcintr: block %d != blkno %qd\n",
1078 block, fd->sc_blkno);
1079 #ifdef DDB
1080 Debugger();
1081 #endif
1082 }
1083 }
1084 #endif
1085 read = bp->b_flags & B_READ ? 1 : 0;
1086
1087 /*
1088 * Setup pseudo-DMA address & count
1089 */
1090 fddmaaddr = (char *)bp->b_data + fd->sc_skip;
1091 fddmalen = fd->sc_nbytes;
1092
1093 wrt_fdc_reg(fdctl, type->rate);
1094 #ifdef FD_DEBUG
1095 printf("fdcintr: %s drive %d track %d head %d sec %d"
1096 " nblks %d\n", read ? "read" : "write",
1097 fd->sc_drive, fd->sc_cylin, head, sec, nblks);
1098 #endif
1099 fdc_ienable();
1100
1101 if (finfo) {
1102 /* formatting */
1103 if (out_fdc(NE7CMD_FORMAT) < 0) {
1104 fdc->sc_errors = 4;
1105 fdcretry(fdc);
1106 goto loop;
1107 }
1108 out_fdc((head << 2) | fd->sc_drive);
1109 out_fdc(finfo->fd_formb_secshift);
1110 out_fdc(finfo->fd_formb_nsecs);
1111 out_fdc(finfo->fd_formb_gaplen);
1112 out_fdc(finfo->fd_formb_fillbyte);
1113 } else {
1114 if (read)
1115 out_fdc(NE7CMD_READ); /* READ */
1116 else
1117 out_fdc(NE7CMD_WRITE); /* WRITE */
1118 out_fdc((head << 2) | fd->sc_drive);
1119 out_fdc(fd->sc_cylin); /* track */
1120 out_fdc(head); /* head */
1121 out_fdc(sec + 1); /* sector +1 */
1122 out_fdc(type->secsize); /* sector size */
1123 out_fdc(sec + nblks); /* last sectors */
1124 out_fdc(type->gap1); /* gap1 size */
1125 out_fdc(type->datalen); /* data length */
1126 }
1127 fdc->sc_state = IOCOMPLETE;
1128
1129 disk_busy(&fd->sc_dk);
1130
1131 /* allow 2 seconds for operation */
1132 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1133 return 1; /* will return later */
1134
1135 case SEEKWAIT:
1136 callout_stop(&fdc->sc_timo_ch);
1137 fdc->sc_state = SEEKCOMPLETE;
1138 /* allow 1/50 second for heads to settle */
1139 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1140 return 1;
1141
1142 case SEEKCOMPLETE:
1143 /* no data on seek */
1144 disk_unbusy(&fd->sc_dk, 0, 0);
1145
1146 /* Make sure seek really happened. */
1147 out_fdc(NE7CMD_SENSEI);
1148 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1149 cyl != bp->b_cylinder * fd->sc_type->step) {
1150 #ifdef FD_DEBUG
1151 fdcstatus(&fd->sc_dev, 2, "seek failed");
1152 #endif
1153 fdcretry(fdc);
1154 goto loop;
1155 }
1156 fd->sc_cylin = bp->b_cylinder;
1157 goto doio;
1158
1159 case IOTIMEDOUT:
1160 case SEEKTIMEDOUT:
1161 case RECALTIMEDOUT:
1162 case RESETTIMEDOUT:
1163 fdcretry(fdc);
1164 goto loop;
1165
1166 case IOCOMPLETE: /* IO DONE, post-analyze */
1167 callout_stop(&fdc->sc_timo_ch);
1168
1169 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
1170 (bp->b_flags & B_READ));
1171
1172 if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) {
1173 /*
1174 * As the damn chip doesn't seem to have a FIFO,
1175 * accept a few overruns as a fact of life *sigh*
1176 */
1177 if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) {
1178 fdc->sc_state = DOSEEK;
1179 goto loop;
1180 }
1181 #ifdef FD_DEBUG
1182 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1183 "read failed" : "write failed");
1184 printf("blkno %qd nblks %d\n",
1185 fd->sc_blkno, fd->sc_nblks);
1186 #endif
1187 fdcretry(fdc);
1188 goto loop;
1189 }
1190 if (fdc->sc_errors) {
1191 diskerr(bp, "fd", "soft error", LOG_PRINTF,
1192 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1193 printf("\n");
1194 fdc->sc_errors = 0;
1195 }
1196 fdc->sc_overruns = 0;
1197 fd->sc_blkno += fd->sc_nblks;
1198 fd->sc_skip += fd->sc_nbytes;
1199 fd->sc_bcount -= fd->sc_nbytes;
1200 if (!finfo && fd->sc_bcount > 0) {
1201 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1202 goto doseek;
1203 }
1204 fdfinish(fd, bp);
1205 goto loop;
1206
1207 case DORESET:
1208 /* try a reset, keep motor on */
1209 fd_set_motor(fdc, 1);
1210 delay(100);
1211 fd_set_motor(fdc, 0);
1212 fdc->sc_state = RESETCOMPLETE;
1213 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1214 return 1; /* will return later */
1215
1216 case RESETCOMPLETE:
1217 callout_stop(&fdc->sc_timo_ch);
1218 /* clear the controller output buffer */
1219 for (i = 0; i < 4; i++) {
1220 out_fdc(NE7CMD_SENSEI);
1221 (void) fdcresult(fdc);
1222 }
1223
1224 /* fall through */
1225 case DORECAL:
1226 fdc_ienable();
1227
1228 out_fdc(NE7CMD_RECAL); /* recalibrate function */
1229 out_fdc(fd->sc_drive);
1230 fdc->sc_state = RECALWAIT;
1231 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1232 return 1; /* will return later */
1233
1234 case RECALWAIT:
1235 callout_stop(&fdc->sc_timo_ch);
1236 fdc->sc_state = RECALCOMPLETE;
1237 /* allow 1/30 second for heads to settle */
1238 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1239 return 1; /* will return later */
1240
1241 case RECALCOMPLETE:
1242 out_fdc(NE7CMD_SENSEI);
1243 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1244 #ifdef FD_DEBUG
1245 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1246 #endif
1247 fdcretry(fdc);
1248 goto loop;
1249 }
1250 fd->sc_cylin = 0;
1251 goto doseek;
1252
1253 case MOTORWAIT:
1254 if (fd->sc_flags & FD_MOTOR_WAIT)
1255 return 1; /* time's not up yet */
1256 goto doseek;
1257
1258 default:
1259 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1260 return 1;
1261 }
1262 #ifdef DIAGNOSTIC
1263 panic("fdcintr: impossible");
1264 #endif
1265 #undef st0
1266 #undef st1
1267 #undef cyl
1268 }
1269
1270 void
1271 fdcretry(fdc)
1272 struct fdc_softc *fdc;
1273 {
1274 char bits[64];
1275 struct fd_softc *fd;
1276 struct buf *bp;
1277
1278 fd = fdc->sc_drives.tqh_first;
1279 bp = BUFQ_PEEK(fd->sc_q);
1280
1281 if (fd->sc_opts & FDOPT_NORETRY)
1282 goto fail;
1283
1284 switch (fdc->sc_errors) {
1285 case 0:
1286 /* try again */
1287 fdc->sc_state = DOSEEK;
1288 break;
1289
1290 case 1: case 2: case 3:
1291 /* didn't work; try recalibrating */
1292 fdc->sc_state = DORECAL;
1293 break;
1294
1295 case 4:
1296 /* still no go; reset the bastard */
1297 fdc->sc_state = DORESET;
1298 break;
1299
1300 default:
1301 fail:
1302 if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1303 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1304 fd->sc_skip / FDC_BSIZE,
1305 (struct disklabel *)NULL);
1306
1307 printf(" (st0 %s",
1308 bitmask_snprintf(fdc->sc_status[0],
1309 NE7_ST0BITS, bits,
1310 sizeof(bits)));
1311 printf(" st1 %s",
1312 bitmask_snprintf(fdc->sc_status[1],
1313 NE7_ST1BITS, bits,
1314 sizeof(bits)));
1315 printf(" st2 %s",
1316 bitmask_snprintf(fdc->sc_status[2],
1317 NE7_ST2BITS, bits,
1318 sizeof(bits)));
1319 printf(" cyl %d head %d sec %d)\n",
1320 fdc->sc_status[3],
1321 fdc->sc_status[4],
1322 fdc->sc_status[5]);
1323 }
1324 bp->b_error = EIO;
1325 fdfinish(fd, bp);
1326 }
1327 fdc->sc_errors++;
1328 }
1329
1330 int
1331 fdioctl(dev, cmd, addr, flag, l)
1332 dev_t dev;
1333 u_long cmd;
1334 void *addr;
1335 int flag;
1336 struct lwp *l;
1337 {
1338 struct fd_softc *fd;
1339 struct disklabel buffer;
1340 int error;
1341 struct fdformat_parms *form_parms;
1342 struct fdformat_cmd *form_cmd;
1343 struct ne7_fd_formb *fd_formb;
1344 unsigned int scratch;
1345 int il[FD_MAX_NSEC + 1];
1346 register int i, j;
1347
1348 fd = hdfd_cd.cd_devs[FDUNIT(dev)];
1349
1350 switch (cmd) {
1351 case DIOCGDINFO:
1352 fdgetdisklabel(fd, dev);
1353 *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1354 return 0;
1355
1356 case DIOCGPART:
1357 fdgetdisklabel(fd, dev);
1358 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1359 ((struct partinfo *)addr)->part =
1360 &fd->sc_dk.dk_label->d_partitions[RAW_PART];
1361 return(0);
1362
1363 case DIOCWLABEL:
1364 if ((flag & FWRITE) == 0)
1365 return EBADF;
1366 /* XXX do something */
1367 return 0;
1368
1369 case DIOCSDINFO:
1370 case DIOCWDINFO:
1371 if ((flag & FWRITE) == 0)
1372 return EBADF;
1373
1374 fd->sc_flags &= ~FD_HAVELAB; /* Invalid */
1375 error = setdisklabel(&buffer, (struct disklabel *)addr, 0,NULL);
1376 if (error)
1377 return error;
1378
1379 if (cmd == DIOCWDINFO)
1380 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1381 return error;
1382
1383 case FDIOCGETFORMAT:
1384 form_parms = (struct fdformat_parms *)addr;
1385 form_parms->fdformat_version = FDFORMAT_VERSION;
1386 form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1387 form_parms->ncyl = fd->sc_type->tracks;
1388 form_parms->nspt = fd->sc_type->sectrac;
1389 form_parms->ntrk = fd->sc_type->heads;
1390 form_parms->stepspercyl = fd->sc_type->step;
1391 form_parms->gaplen = fd->sc_type->gap2;
1392 form_parms->fillbyte = fd->sc_type->fillbyte;
1393 form_parms->interleave = fd->sc_type->interleave;
1394 switch (fd->sc_type->rate) {
1395 case FDC_500KBPS:
1396 form_parms->xfer_rate = 500 * 1024;
1397 break;
1398 case FDC_300KBPS:
1399 form_parms->xfer_rate = 300 * 1024;
1400 break;
1401 case FDC_250KBPS:
1402 form_parms->xfer_rate = 250 * 1024;
1403 break;
1404 case FDC_125KBPS:
1405 form_parms->xfer_rate = 125 * 1024;
1406 break;
1407 default:
1408 return EINVAL;
1409 }
1410 return 0;
1411
1412 case FDIOCSETFORMAT:
1413 if((flag & FWRITE) == 0)
1414 return EBADF; /* must be opened for writing */
1415 form_parms = (struct fdformat_parms *)addr;
1416 if (form_parms->fdformat_version != FDFORMAT_VERSION)
1417 return EINVAL; /* wrong version of formatting prog */
1418
1419 scratch = form_parms->nbps >> 7;
1420 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1421 scratch & ~(1 << (ffs(scratch)-1)))
1422 /* not a power-of-two multiple of 128 */
1423 return EINVAL;
1424
1425 switch (form_parms->xfer_rate) {
1426 case 500 * 1024:
1427 fd->sc_type->rate = FDC_500KBPS;
1428 break;
1429 case 300 * 1024:
1430 fd->sc_type->rate = FDC_300KBPS;
1431 break;
1432 case 250 * 1024:
1433 fd->sc_type->rate = FDC_250KBPS;
1434 break;
1435 case 125 * 1024:
1436 fd->sc_type->rate = FDC_125KBPS;
1437 break;
1438 default:
1439 return EINVAL;
1440 }
1441
1442 if (form_parms->nspt > FD_MAX_NSEC ||
1443 form_parms->fillbyte > 0xff ||
1444 form_parms->interleave > 0xff)
1445 return EINVAL;
1446 fd->sc_type->sectrac = form_parms->nspt;
1447 if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1448 return EINVAL;
1449 fd->sc_type->heads = form_parms->ntrk;
1450 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1451 fd->sc_type->secsize = ffs(scratch)-1;
1452 fd->sc_type->gap2 = form_parms->gaplen;
1453 fd->sc_type->tracks = form_parms->ncyl;
1454 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1455 form_parms->nbps / DEV_BSIZE;
1456 fd->sc_type->step = form_parms->stepspercyl;
1457 fd->sc_type->fillbyte = form_parms->fillbyte;
1458 fd->sc_type->interleave = form_parms->interleave;
1459 return 0;
1460
1461 case FDIOCFORMAT_TRACK:
1462 if((flag & FWRITE) == 0)
1463 return EBADF; /* must be opened for writing */
1464 form_cmd = (struct fdformat_cmd *)addr;
1465 if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1466 return EINVAL; /* wrong version of formatting prog */
1467
1468 if (form_cmd->head >= fd->sc_type->heads ||
1469 form_cmd->cylinder >= fd->sc_type->tracks) {
1470 return EINVAL;
1471 }
1472
1473 fd_formb = malloc(sizeof(struct ne7_fd_formb),
1474 M_TEMP, M_NOWAIT);
1475 if (fd_formb == 0)
1476 return ENOMEM;
1477
1478 fd_formb->head = form_cmd->head;
1479 fd_formb->cyl = form_cmd->cylinder;
1480 fd_formb->transfer_rate = fd->sc_type->rate;
1481 fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1482 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1483 fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1484 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1485
1486 bzero(il,sizeof il);
1487 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1488 while (il[(j%fd_formb->fd_formb_nsecs)+1])
1489 j++;
1490 il[(j%fd_formb->fd_formb_nsecs)+1] = i;
1491 j += fd->sc_type->interleave;
1492 }
1493 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1494 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1495 fd_formb->fd_formb_headno(i) = form_cmd->head;
1496 fd_formb->fd_formb_secno(i) = il[i+1];
1497 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1498 }
1499
1500 error = fdformat(dev, fd_formb, l->l_proc);
1501 free(fd_formb, M_TEMP);
1502 return error;
1503
1504 case FDIOCGETOPTS: /* get drive options */
1505 *(int *)addr = fd->sc_opts;
1506 return 0;
1507
1508 case FDIOCSETOPTS: /* set drive options */
1509 fd->sc_opts = *(int *)addr;
1510 return 0;
1511
1512
1513 default:
1514 return ENOTTY;
1515 }
1516
1517 #ifdef DIAGNOSTIC
1518 panic("fdioctl: impossible");
1519 #endif
1520 }
1521
1522 int
1523 fdformat(dev, finfo, p)
1524 dev_t dev;
1525 struct ne7_fd_formb *finfo;
1526 struct proc *p;
1527 {
1528 int rv = 0, s;
1529 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
1530 struct fd_type *type = fd->sc_type;
1531 struct buf *bp;
1532
1533 /* set up a buffer header for fdstrategy() */
1534 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1535 if(bp == 0)
1536 return ENOBUFS;
1537 bzero((void *)bp, sizeof(struct buf));
1538 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1539 bp->b_proc = p;
1540 bp->b_dev = dev;
1541
1542 /*
1543 * calculate a fake blkno, so fdstrategy() would initiate a
1544 * seek to the requested cylinder
1545 */
1546 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1547 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1548
1549 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1550 bp->b_data = (void *)finfo;
1551
1552 #ifdef DEBUG
1553 printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount);
1554 #endif
1555
1556 /* now do the format */
1557 fdstrategy(bp);
1558
1559 /* ...and wait for it to complete */
1560 s = splbio();
1561 while(!(bp->b_flags & B_DONE)) {
1562 rv = tsleep((void *)bp, PRIBIO, "fdform", 20 * hz);
1563 if (rv == EWOULDBLOCK)
1564 break;
1565 }
1566 splx(s);
1567
1568 if (rv == EWOULDBLOCK) {
1569 /* timed out */
1570 rv = EIO;
1571 biodone(bp);
1572 } else if (bp->b_error != 0) {
1573 rv = bp->b_error;
1574 }
1575 free(bp, M_TEMP);
1576 return rv;
1577 }
1578
1579
1580 /*
1581 * Obtain a disklabel. Either a real one from the disk or, if there
1582 * is none, a fake one.
1583 */
1584 static void
1585 fdgetdisklabel(fd, dev)
1586 struct fd_softc *fd;
1587 dev_t dev;
1588 {
1589 struct disklabel *lp;
1590 struct cpu_disklabel cpulab;
1591
1592 if (fd->sc_flags & FD_HAVELAB)
1593 return; /* Already got one */
1594
1595 lp = fd->sc_dk.dk_label;
1596
1597 bzero(lp, sizeof(*lp));
1598 bzero(&cpulab, sizeof(cpulab));
1599
1600 lp->d_secpercyl = fd->sc_type->seccyl;
1601 lp->d_type = DTYPE_FLOPPY;
1602 lp->d_secsize = FDC_BSIZE;
1603 lp->d_secperunit = fd->sc_type->size;
1604
1605 /*
1606 * If there is no label on the disk: fake one
1607 */
1608 if (readdisklabel(dev, fdstrategy, lp, &cpulab) != NULL)
1609 fdgetdefaultlabel(fd, lp, RAW_PART);
1610 fd->sc_flags |= FD_HAVELAB;
1611
1612 if ((FDC_BSIZE * fd->sc_type->size)
1613 < (lp->d_secsize * lp->d_secperunit)) {
1614 /*
1615 * XXX: Ignore these fields. If you drop a vnddisk
1616 * on more than one floppy, you'll get disturbing
1617 * sounds!
1618 */
1619 lp->d_secpercyl = fd->sc_type->seccyl;
1620 lp->d_type = DTYPE_FLOPPY;
1621 lp->d_secsize = FDC_BSIZE;
1622 lp->d_secperunit = fd->sc_type->size;
1623 }
1624 }
1625
1626 /*
1627 * Build defaultdisk label. For now we only create a label from what we
1628 * know from 'sc'.
1629 */
1630 static void
1631 fdgetdefaultlabel(fd, lp, part)
1632 struct fd_softc *fd;
1633 struct disklabel *lp;
1634 int part;
1635 {
1636 bzero(lp, sizeof(struct disklabel));
1637
1638 lp->d_secsize = 128 * (1 << fd->sc_type->secsize);
1639 lp->d_ntracks = fd->sc_type->heads;
1640 lp->d_nsectors = fd->sc_type->sectrac;
1641 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1642 lp->d_ncylinders = fd->sc_type->size / lp->d_secpercyl;
1643 lp->d_secperunit = fd->sc_type->size;
1644
1645 lp->d_type = DTYPE_FLOPPY;
1646 lp->d_rpm = 300; /* good guess I suppose. */
1647 lp->d_interleave = 1; /* FIXME: is this OK? */
1648 lp->d_bbsize = 0;
1649 lp->d_sbsize = 0;
1650 lp->d_npartitions = part + 1;
1651 lp->d_trkseek = 6000; /* Who cares... */
1652 lp->d_magic = DISKMAGIC;
1653 lp->d_magic2 = DISKMAGIC;
1654 lp->d_checksum = dkcksum(lp);
1655 lp->d_partitions[part].p_size = lp->d_secperunit;
1656 lp->d_partitions[part].p_fstype = FS_UNUSED;
1657 lp->d_partitions[part].p_fsize = 1024;
1658 lp->d_partitions[part].p_frag = 8;
1659 }
1660