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