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