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