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