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