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