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