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