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