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