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