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