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