Annotation of sys/arch/sparc64/dev/fd.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: fd.c,v 1.18 2007/06/20 18:15:46 deraadt Exp $ */
2: /* $NetBSD: fd.c,v 1.112 2003/08/07 16:29:35 agc Exp $ */
3:
4: /*-
5: * Copyright (c) 2000 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Paul Kranenburg.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: /*-
41: * Copyright (c) 1990 The Regents of the University of California.
42: * All rights reserved.
43: *
44: * This code is derived from software contributed to Berkeley by
45: * Don Ahn.
46: *
47: * Redistribution and use in source and binary forms, with or without
48: * modification, are permitted provided that the following conditions
49: * are met:
50: * 1. Redistributions of source code must retain the above copyright
51: * notice, this list of conditions and the following disclaimer.
52: * 2. Redistributions in binary form must reproduce the above copyright
53: * notice, this list of conditions and the following disclaimer in the
54: * documentation and/or other materials provided with the distribution.
55: * 3. Neither the name of the University nor the names of its contributors
56: * may be used to endorse or promote products derived from this software
57: * without specific prior written permission.
58: *
59: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69: * SUCH DAMAGE.
70: *
71: * @(#)fd.c 7.4 (Berkeley) 5/25/91
72: */
73:
74: /*-
75: * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.
76: * Copyright (c) 1995 Paul Kranenburg.
77: *
78: * This code is derived from software contributed to Berkeley by
79: * Don Ahn.
80: *
81: * Redistribution and use in source and binary forms, with or without
82: * modification, are permitted provided that the following conditions
83: * are met:
84: * 1. Redistributions of source code must retain the above copyright
85: * notice, this list of conditions and the following disclaimer.
86: * 2. Redistributions in binary form must reproduce the above copyright
87: * notice, this list of conditions and the following disclaimer in the
88: * documentation and/or other materials provided with the distribution.
89: * 3. All advertising materials mentioning features or use of this software
90: * must display the following acknowledgement:
91: * This product includes software developed by the University of
92: * California, Berkeley and its contributors.
93: * 4. Neither the name of the University nor the names of its contributors
94: * may be used to endorse or promote products derived from this software
95: * without specific prior written permission.
96: *
97: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
98: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
99: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
100: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
101: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
102: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
103: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
104: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
105: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
106: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
107: * SUCH DAMAGE.
108: *
109: * @(#)fd.c 7.4 (Berkeley) 5/25/91
110: */
111:
112: #include <sys/param.h>
113: #include <sys/systm.h>
114: #include <sys/timeout.h>
115: #include <sys/kernel.h>
116: #include <sys/file.h>
117: #include <sys/ioctl.h>
118: #include <sys/conf.h>
119: #include <sys/device.h>
120: #include <sys/disklabel.h>
121: #include <sys/disk.h>
122: #include <sys/buf.h>
123: #include <sys/malloc.h>
124: #include <sys/proc.h>
125: #include <sys/uio.h>
126: #include <sys/mtio.h>
127: #include <sys/stat.h>
128: #include <sys/syslog.h>
129: #include <sys/queue.h>
130:
131: #include <dev/cons.h>
132:
133: #include <uvm/uvm_extern.h>
134:
135: #include <machine/autoconf.h>
136: #include <machine/conf.h>
137: #include <machine/intr.h>
138: #include <machine/ioctl_fd.h>
139:
140: #include <sparc64/dev/auxioreg.h>
141: #include <sparc64/dev/auxiovar.h>
142: #include <sparc64/dev/ebusreg.h>
143: #include <sparc64/dev/ebusvar.h>
144: #include <sparc64/dev/fdreg.h>
145: #include <sparc64/dev/fdvar.h>
146:
147: #define FDUNIT(dev) ((minor(dev) / MAXPARTITIONS) / 8)
148: #define FDTYPE(dev) ((minor(dev) / MAXPARTITIONS) % 8)
149:
150: #define FTC_FLIP \
151: do { \
152: auxio_fd_control(AUXIO_LED_FTC); \
153: auxio_fd_control(0); \
154: } while (0)
155:
156: /* XXX misuse a flag to identify format operation */
157: #define B_FORMAT B_XXX
158:
159: #ifdef FD_DEBUG
160: int fdc_debug = 0;
161: #endif
162:
163: enum fdc_state {
164: DEVIDLE = 0,
165: MOTORWAIT, /* 1 */
166: DOSEEK, /* 2 */
167: SEEKWAIT, /* 3 */
168: SEEKTIMEDOUT, /* 4 */
169: SEEKCOMPLETE, /* 5 */
170: DOIO, /* 6 */
171: IOCOMPLETE, /* 7 */
172: IOTIMEDOUT, /* 8 */
173: IOCLEANUPWAIT, /* 9 */
174: IOCLEANUPTIMEDOUT,/*10 */
175: DORESET, /* 11 */
176: RESETCOMPLETE, /* 12 */
177: RESETTIMEDOUT, /* 13 */
178: DORECAL, /* 14 */
179: RECALWAIT, /* 15 */
180: RECALTIMEDOUT, /* 16 */
181: RECALCOMPLETE, /* 17 */
182: DODSKCHG, /* 18 */
183: DSKCHGWAIT, /* 19 */
184: DSKCHGTIMEDOUT, /* 20 */
185: };
186:
187: /* software state, per controller */
188: struct fdc_softc {
189: struct device sc_dev; /* boilerplate */
190: bus_space_tag_t sc_bustag;
191:
192: struct timeout fdctimeout_to;
193: struct timeout fdcpseudointr_to;
194:
195: struct fd_softc *sc_fd[4]; /* pointers to children */
196: TAILQ_HEAD(drivehead, fd_softc) sc_drives;
197: enum fdc_state sc_state;
198: int sc_flags;
199: #define FDC_EBUS 0x01
200: #define FDC_NEEDHEADSETTLE 0x02
201: #define FDC_EIS 0x04
202: #define FDC_NEEDMOTORWAIT 0x08
203: #define FDC_NOEJECT 0x10
204: int sc_errors; /* number of retries so far */
205: int sc_overruns; /* number of DMA overruns */
206: int sc_cfg; /* current configuration */
207: struct fdcio sc_io;
208: #define sc_handle sc_io.fdcio_handle
209: #define sc_itask sc_io.fdcio_itask
210: #define sc_istatus sc_io.fdcio_istatus
211: #define sc_data sc_io.fdcio_data
212: #define sc_tc sc_io.fdcio_tc
213: #define sc_nstat sc_io.fdcio_nstat
214: #define sc_status sc_io.fdcio_status
215:
216: void *sc_sicookie; /* softintr(9) cookie */
217: };
218:
219: /* controller driver configuration */
220: int fdcmatch_sbus(struct device *, void *, void *);
221: int fdcmatch_ebus(struct device *, void *, void *);
222: void fdcattach_sbus(struct device *, struct device *, void *);
223: void fdcattach_ebus(struct device *, struct device *, void *);
224:
225: int fdcattach(struct fdc_softc *, int);
226:
227: struct cfattach fdc_sbus_ca = {
228: sizeof(struct fdc_softc), fdcmatch_sbus, fdcattach_sbus
229: };
230:
231: struct cfattach fdc_ebus_ca = {
232: sizeof(struct fdc_softc), fdcmatch_ebus, fdcattach_ebus
233: };
234:
235: struct cfdriver fdc_cd = {
236: NULL, "fdc", DV_DULL
237: };
238:
239: __inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
240:
241: /* The order of entries in the following table is important -- BEWARE! */
242: struct fd_type fd_types[] = {
243: { 18,2,36,2,0xff,0xcf,0x1b,0x54,80,2880,1,FDC_500KBPS, "1.44MB" }, /* 1.44MB diskette */
244: { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
245: { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
246: { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/NEC" } /* 1.2 MB japanese format */
247: };
248:
249: /* software state, per disk (with up to 4 disks per ctlr) */
250: struct fd_softc {
251: struct device sc_dv; /* generic device info */
252: struct disk sc_dk; /* generic disk info */
253:
254: struct fd_type *sc_deftype; /* default type descriptor */
255: struct fd_type *sc_type; /* current type descriptor */
256:
257: struct timeout sc_motoron_to;
258: struct timeout sc_motoroff_to;
259:
260: daddr64_t sc_blkno; /* starting block number */
261: int sc_bcount; /* byte count left */
262: int sc_skip; /* bytes already transferred */
263: int sc_nblks; /* number of blocks currently transferring */
264: int sc_nbytes; /* number of bytes currently transferring */
265:
266: int sc_drive; /* physical unit number */
267: int sc_flags;
268: #define FD_OPEN 0x01 /* it's open */
269: #define FD_MOTOR 0x02 /* motor should be on */
270: #define FD_MOTOR_WAIT 0x04 /* motor coming up */
271: int sc_cylin; /* where we think the head is */
272: int sc_opts; /* user-set options */
273:
274: void *sc_sdhook; /* shutdownhook cookie */
275:
276: TAILQ_ENTRY(fd_softc) sc_drivechain;
277: int sc_ops; /* I/O ops since last switch */
278: struct buf sc_q; /* pending I/O requests */
279: };
280:
281: /* floppy driver configuration */
282: int fdmatch(struct device *, void *, void *);
283: void fdattach(struct device *, struct device *, void *);
284:
285: struct cfattach fd_ca = {
286: sizeof(struct fd_softc), fdmatch, fdattach
287: };
288:
289: struct cfdriver fd_cd = {
290: NULL, "fd", DV_DISK
291: };
292:
293: void fdgetdisklabel(dev_t);
294: int fd_get_parms(struct fd_softc *);
295: void fdstrategy(struct buf *);
296: void fdstart(struct fd_softc *);
297: int fdprint(void *, const char *);
298:
299: struct dkdriver fddkdriver = { fdstrategy };
300:
301: struct fd_type *fd_nvtotype(char *, int, int);
302: void fd_set_motor(struct fdc_softc *fdc);
303: void fd_motor_off(void *arg);
304: void fd_motor_on(void *arg);
305: int fdcresult(struct fdc_softc *fdc);
306: int fdc_wrfifo(struct fdc_softc *fdc, u_char x);
307: void fdcstart(struct fdc_softc *fdc);
308: void fdcstatus(struct fdc_softc *fdc, char *s);
309: void fdc_reset(struct fdc_softc *fdc);
310: int fdc_diskchange(struct fdc_softc *fdc);
311: void fdctimeout(void *arg);
312: void fdcpseudointr(void *arg);
313: int fdchwintr(void *);
314: void fdcswintr(void *);
315: int fdcstate(struct fdc_softc *);
316: void fdcretry(struct fdc_softc *fdc);
317: void fdfinish(struct fd_softc *fd, struct buf *bp);
318: int fdformat(dev_t, struct fd_formb *, struct proc *);
319: void fd_do_eject(struct fd_softc *);
320: static int fdconf(struct fdc_softc *);
321:
322: int
323: fdcmatch_sbus(parent, match, aux)
324: struct device *parent;
325: void *match, *aux;
326: {
327: struct sbus_attach_args *sa = aux;
328:
329: return (strcmp("SUNW,fdtwo", sa->sa_name) == 0);
330: }
331:
332: void
333: fdcattach_sbus(parent, self, aux)
334: struct device *parent, *self;
335: void *aux;
336: {
337: struct fdc_softc *fdc = (void *)self;
338: struct sbus_attach_args *sa = aux;
339:
340: if (sa->sa_nintr == 0) {
341: printf(": no interrupt line configured\n");
342: return;
343: }
344:
345: if (auxio_fd_control(0) != 0) {
346: printf(": can't attach before auxio\n");
347: return;
348: }
349:
350: fdc->sc_bustag = sa->sa_bustag;
351:
352: if (sbus_bus_map(sa->sa_bustag,
353: sa->sa_slot, sa->sa_offset, sa->sa_size,
354: BUS_SPACE_MAP_LINEAR, 0, &fdc->sc_handle) != 0) {
355: printf(": cannot map control registers\n");
356: return;
357: }
358:
359: if (strcmp(getpropstring(sa->sa_node, "status"), "disabled") == 0) {
360: printf(": no drives attached\n");
361: return;
362: }
363:
364: if (getproplen(sa->sa_node, "manual") >= 0)
365: fdc->sc_flags |= FDC_NOEJECT;
366:
367: if (fdcattach(fdc, sa->sa_pri) != 0)
368: bus_space_unmap(sa->sa_bustag, fdc->sc_handle, sa->sa_size);
369: }
370:
371: int
372: fdcmatch_ebus(parent, match, aux)
373: struct device *parent;
374: void *match, *aux;
375: {
376: struct ebus_attach_args *ea = aux;
377:
378: return (strcmp("fdthree", ea->ea_name) == 0);
379: }
380:
381: void
382: fdcattach_ebus(parent, self, aux)
383: struct device *parent, *self;
384: void *aux;
385: {
386: struct fdc_softc *fdc = (void *)self;
387: struct ebus_attach_args *ea = aux;
388:
389: if (ea->ea_nintrs == 0) {
390: printf(": no interrupt line configured\n");
391: return;
392: }
393:
394: if (ea->ea_nregs < 3) {
395: printf(": expected 3 registers, only got %d\n",
396: ea->ea_nregs);
397: return;
398: }
399:
400: if (ea->ea_nvaddrs > 0) {
401: if (bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
402: BUS_SPACE_MAP_PROMADDRESS, &fdc->sc_handle) != 0) {
403: printf(": can't map control registers\n");
404: return;
405: }
406: fdc->sc_bustag = ea->ea_memtag;
407: } else if (ebus_bus_map(ea->ea_memtag, 0,
408: EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
409: ea->ea_regs[0].size, 0, 0, &fdc->sc_handle) == 0) {
410: fdc->sc_bustag = ea->ea_memtag;
411: } else if (ebus_bus_map(ea->ea_iotag, 0,
412: EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
413: ea->ea_regs[0].size, 0, 0, &fdc->sc_handle) == 0) {
414: fdc->sc_bustag = ea->ea_iotag;
415: } else {
416: printf(": can't map control registers\n");
417: return;
418: }
419:
420: if (strcmp(getpropstring(ea->ea_node, "status"), "disabled") == 0) {
421: printf(": no drives attached\n");
422: return;
423: }
424:
425: fdc->sc_flags |= FDC_EBUS;
426:
427: if (getproplen(ea->ea_node, "manual") >= 0)
428: fdc->sc_flags |= FDC_NOEJECT;
429:
430: /* XXX unmapping if it fails */
431: fdcattach(fdc, ea->ea_intrs[0]);
432: }
433:
434: /*
435: * Arguments passed between fdcattach and fdprobe.
436: */
437: struct fdc_attach_args {
438: int fa_drive;
439: struct fd_type *fa_deftype;
440: };
441:
442: /*
443: * Print the location of a disk drive (called just before attaching the
444: * the drive). If `fdc' is not NULL, the drive was found but was not
445: * in the system config file; print the drive name as well.
446: * Return QUIET (config_find ignores this if the device was configured) to
447: * avoid printing `fdN not configured' messages.
448: */
449: int
450: fdprint(aux, fdc)
451: void *aux;
452: const char *fdc;
453: {
454: register struct fdc_attach_args *fa = aux;
455:
456: if (!fdc)
457: printf(" drive %d", fa->fa_drive);
458: return (QUIET);
459: }
460:
461: /*
462: * Configure several parameters and features on the FDC.
463: * Return 0 on success.
464: */
465: static int
466: fdconf(fdc)
467: struct fdc_softc *fdc;
468: {
469: int vroom;
470:
471: if (fdc_wrfifo(fdc, NE7CMD_DUMPREG) || fdcresult(fdc) != 10)
472: return (-1);
473:
474: /*
475: * dumpreg[7] seems to be a motor-off timeout; set it to whatever
476: * the PROM thinks is appropriate.
477: */
478: if ((vroom = fdc->sc_status[7]) == 0)
479: vroom = 0x64;
480:
481: /* Configure controller to use FIFO and Implied Seek */
482: if (fdc_wrfifo(fdc, NE7CMD_CFG) != 0)
483: return (-1);
484: if (fdc_wrfifo(fdc, vroom) != 0)
485: return (-1);
486: if (fdc_wrfifo(fdc, fdc->sc_cfg) != 0)
487: return (-1);
488: if (fdc_wrfifo(fdc, 0) != 0) /* PRETRK */
489: return (-1);
490: /* No result phase for the NE7CMD_CFG command */
491:
492: /* Lock configuration across soft resets. */
493: if (fdc_wrfifo(fdc, NE7CMD_LOCK | CFG_LOCK) != 0 ||
494: fdcresult(fdc) != 1) {
495: #ifdef FD_DEBUG
496: printf("fdconf: CFGLOCK failed");
497: #endif
498: return (-1);
499: }
500:
501: return (0);
502: #if 0
503: if (fdc_wrfifo(fdc, NE7CMD_VERSION) == 0 &&
504: fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x90) {
505: if (fdc_debug)
506: printf("[version cmd]");
507: }
508: #endif
509: }
510:
511: int
512: fdcattach(fdc, pri)
513: struct fdc_softc *fdc;
514: int pri;
515: {
516: struct fdc_attach_args fa;
517: int drive_attached;
518:
519: timeout_set(&fdc->fdctimeout_to, fdctimeout, fdc);
520: timeout_set(&fdc->fdcpseudointr_to, fdcpseudointr, fdc);
521:
522: fdc->sc_state = DEVIDLE;
523: fdc->sc_itask = FDC_ITASK_NONE;
524: fdc->sc_istatus = FDC_ISTATUS_NONE;
525: fdc->sc_flags |= FDC_EIS | FDC_NEEDMOTORWAIT;
526: TAILQ_INIT(&fdc->sc_drives);
527:
528: /*
529: * Configure controller; enable FIFO, Implied seek, no POLL mode?.
530: * Note: CFG_EFIFO is active-low, initial threshold value: 8
531: */
532: fdc->sc_cfg = CFG_EIS|/*CFG_EFIFO|*/CFG_POLL|(8 & CFG_THRHLD_MASK);
533: if (fdconf(fdc) != 0) {
534: printf("\n%s: no drives attached\n", fdc->sc_dev.dv_xname);
535: return (-1);
536: }
537:
538: if (bus_intr_establish(fdc->sc_bustag, pri, IPL_BIO,
539: 0, fdchwintr, fdc, fdc->sc_dev.dv_xname) == NULL) {
540: printf("\n%s: cannot register interrupt handler\n",
541: fdc->sc_dev.dv_xname);
542: return (-1);
543: }
544:
545: fdc->sc_sicookie = softintr_establish(IPL_BIO, fdcswintr, fdc);
546: if (fdc->sc_sicookie == NULL) {
547: printf("\n%s: cannot register soft interrupt handler\n",
548: fdc->sc_dev.dv_xname);
549: return (-1);
550: }
551:
552: printf(" softpri %d", PIL_FDSOFT);
553: if (fdc->sc_flags & FDC_NOEJECT)
554: printf(": manual eject");
555: printf("\n");
556:
557: /* physical limit: four drives per controller. */
558: drive_attached = 0;
559: for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
560: fa.fa_deftype = NULL; /* unknown */
561: fa.fa_deftype = &fd_types[0]; /* XXX */
562: if (config_found(&fdc->sc_dev, (void *)&fa, fdprint) != NULL)
563: drive_attached = 1;
564: }
565:
566: if (drive_attached == 0) {
567: /* XXX - dis-establish interrupts here */
568: /* return (-1); */
569: }
570:
571: return (0);
572: }
573:
574: int
575: fdmatch(parent, match, aux)
576: struct device *parent;
577: void *match;
578: void *aux;
579: {
580: struct fdc_softc *fdc = (void *)parent;
581: bus_space_tag_t t = fdc->sc_bustag;
582: bus_space_handle_t h = fdc->sc_handle;
583: struct fdc_attach_args *fa = aux;
584: int drive = fa->fa_drive;
585: int n, ok;
586:
587: if (drive > 0)
588: /* XXX - for now, punt on more than one drive */
589: return (0);
590:
591: /* select drive and turn on motor */
592: bus_space_write_1(t, h, FDREG77_DOR,
593: drive | FDO_FRST | FDO_MOEN(drive));
594: /* wait for motor to spin up */
595: delay(250000);
596:
597: fdc->sc_nstat = 0;
598: fdc_wrfifo(fdc, NE7CMD_RECAL);
599: fdc_wrfifo(fdc, drive);
600:
601: /* Wait for recalibration to complete */
602: for (n = 0; n < 10000; n++) {
603: u_int8_t v;
604:
605: delay(1000);
606: v = bus_space_read_1(t, h, FDREG77_MSR);
607: if ((v & (NE7_RQM|NE7_DIO|NE7_CB)) == NE7_RQM) {
608: /* wait a bit longer till device *really* is ready */
609: delay(100000);
610: if (fdc_wrfifo(fdc, NE7CMD_SENSEI))
611: break;
612: if (fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x80)
613: /*
614: * Got `invalid command'; we interpret it
615: * to mean that the re-calibrate hasn't in
616: * fact finished yet
617: */
618: continue;
619: break;
620: }
621: }
622: n = fdc->sc_nstat;
623: #ifdef FD_DEBUG
624: if (fdc_debug) {
625: int i;
626: printf("fdprobe: %d stati:", n);
627: for (i = 0; i < n; i++)
628: printf(" 0x%x", fdc->sc_status[i]);
629: printf("\n");
630: }
631: #endif
632: ok = (n == 2 && (fdc->sc_status[0] & 0xf8) == 0x20) ? 1 : 0;
633:
634: /* deselect drive and turn motor off */
635: bus_space_write_1(t, h, FDREG77_DOR, FDO_FRST | FDO_DS);
636:
637: return (ok);
638: }
639:
640: /*
641: * Controller is working, and drive responded. Attach it.
642: */
643: void
644: fdattach(parent, self, aux)
645: struct device *parent, *self;
646: void *aux;
647: {
648: struct fdc_softc *fdc = (void *)parent;
649: struct fd_softc *fd = (void *)self;
650: struct fdc_attach_args *fa = aux;
651: struct fd_type *type = fa->fa_deftype;
652: int drive = fa->fa_drive;
653:
654: timeout_set(&fd->sc_motoron_to, fd_motor_on, fd);
655: timeout_set(&fd->sc_motoroff_to, fd_motor_off, fd);
656:
657: /* XXX Allow `flags' to override device type? */
658:
659: if (type)
660: printf(": %s %d cyl, %d head, %d sec\n", type->name,
661: type->tracks, type->heads, type->sectrac);
662: else
663: printf(": density unknown\n");
664:
665: fd->sc_cylin = -1;
666: fd->sc_drive = drive;
667: fd->sc_deftype = type;
668: fdc->sc_fd[drive] = fd;
669:
670: fdc_wrfifo(fdc, NE7CMD_SPECIFY);
671: fdc_wrfifo(fdc, type->steprate);
672: /* XXX head load time == 6ms */
673: fdc_wrfifo(fdc, 6 | NE7_SPECIFY_NODMA);
674:
675: /*
676: * Initialize and attach the disk structure.
677: */
678: fd->sc_dk.dk_name = fd->sc_dv.dv_xname;
679: fd->sc_dk.dk_driver = &fddkdriver;
680: disk_attach(&fd->sc_dk);
681:
682: /* Make sure the drive motor gets turned off at shutdown time. */
683: fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
684: }
685:
686: __inline struct fd_type *
687: fd_dev_to_type(fd, dev)
688: struct fd_softc *fd;
689: dev_t dev;
690: {
691: int type = FDTYPE(dev);
692:
693: if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
694: return (NULL);
695: return (type ? &fd_types[type - 1] : fd->sc_deftype);
696: }
697:
698: void
699: fdstrategy(bp)
700: register struct buf *bp; /* IO operation to perform */
701: {
702: struct fd_softc *fd;
703: int unit = FDUNIT(bp->b_dev);
704: int sz;
705: int s;
706:
707: /* Valid unit, controller, and request? */
708: if (unit >= fd_cd.cd_ndevs ||
709: (fd = fd_cd.cd_devs[unit]) == 0 ||
710: bp->b_blkno < 0 ||
711: (((bp->b_bcount % FD_BSIZE(fd)) != 0 ||
712: (bp->b_blkno * DEV_BSIZE) % FD_BSIZE(fd) != 0) &&
713: (bp->b_flags & B_FORMAT) == 0)) {
714: bp->b_error = EINVAL;
715: goto bad;
716: }
717:
718: /* If it's a null transfer, return immediately. */
719: if (bp->b_bcount == 0)
720: goto done;
721:
722: sz = howmany(bp->b_bcount, DEV_BSIZE);
723:
724: if (bp->b_blkno + sz > (fd->sc_type->size * DEV_BSIZE) / FD_BSIZE(fd)) {
725: sz = (fd->sc_type->size * DEV_BSIZE) / FD_BSIZE(fd)
726: - bp->b_blkno;
727: if (sz == 0) {
728: /* If exactly at end of disk, return EOF. */
729: bp->b_resid = bp->b_bcount;
730: goto done;
731: }
732: if (sz < 0) {
733: /* If past end of disk, return EINVAL. */
734: bp->b_error = EINVAL;
735: goto bad;
736: }
737: /* Otherwise, truncate request. */
738: bp->b_bcount = sz << DEV_BSHIFT;
739: }
740:
741: bp->b_cylinder = (bp->b_blkno * DEV_BSIZE) /
742: (FD_BSIZE(fd) * fd->sc_type->seccyl);
743:
744: #ifdef FD_DEBUG
745: if (fdc_debug > 1)
746: printf("fdstrategy: b_blkno %lld b_bcount %d blkno %lld cylin %d\n",
747: bp->b_blkno, bp->b_bcount,
748: fd->sc_blkno, bp->b_cylinder);
749: #endif
750:
751: /* Queue transfer on drive, activate drive and controller if idle. */
752: s = splbio();
753: disksort(&fd->sc_q, bp);
754: timeout_del(&fd->sc_motoroff_to); /* a good idea */
755: if (!fd->sc_q.b_active)
756: fdstart(fd);
757: #ifdef DIAGNOSTIC
758: else {
759: struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
760: if (fdc->sc_state == DEVIDLE) {
761: printf("fdstrategy: controller inactive\n");
762: fdcstart(fdc);
763: }
764: }
765: #endif
766: splx(s);
767: return;
768:
769: bad:
770: bp->b_flags |= B_ERROR;
771: done:
772: /* Toss transfer; we're done early. */
773: s = splbio();
774: biodone(bp);
775: splx(s);
776: }
777:
778: void
779: fdstart(fd)
780: struct fd_softc *fd;
781: {
782: struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
783: int active = !TAILQ_EMPTY(&fdc->sc_drives);
784:
785: /* Link into controller queue. */
786: fd->sc_q.b_active = 1;
787: TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
788:
789: /* If controller not already active, start it. */
790: if (!active)
791: fdcstart(fdc);
792: }
793:
794: void
795: fdfinish(fd, bp)
796: struct fd_softc *fd;
797: struct buf *bp;
798: {
799: struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
800:
801: /*
802: * Move this drive to the end of the queue to give others a `fair'
803: * chance. We only force a switch if N operations are completed while
804: * another drive is waiting to be serviced, since there is a long motor
805: * startup delay whenever we switch.
806: */
807: if (TAILQ_NEXT(fd, sc_drivechain) != NULL && ++fd->sc_ops >= 8) {
808: fd->sc_ops = 0;
809: TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
810: if (bp->b_actf) {
811: TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
812: } else
813: fd->sc_q.b_active = 0;
814: }
815: bp->b_resid = fd->sc_bcount;
816: fd->sc_skip = 0;
817: fd->sc_q.b_actf = bp->b_actf;
818:
819: biodone(bp);
820: /* turn off motor 5s from now */
821: timeout_add(&fd->sc_motoroff_to, 5 * hz);
822: fdc->sc_state = DEVIDLE;
823: }
824:
825: void
826: fdc_reset(fdc)
827: struct fdc_softc *fdc;
828: {
829: bus_space_tag_t t = fdc->sc_bustag;
830: bus_space_handle_t h = fdc->sc_handle;
831:
832: bus_space_write_1(t, h, FDREG77_DOR, FDO_FDMAEN | FDO_MOEN(0));
833:
834: bus_space_write_1(t, h, FDREG77_DRS, DRS_RESET);
835: delay(10);
836: bus_space_write_1(t, h, FDREG77_DRS, 0);
837:
838: bus_space_write_1(t, h, FDREG77_DOR,
839: FDO_FRST | FDO_FDMAEN | FDO_DS);
840: #ifdef FD_DEBUG
841: if (fdc_debug)
842: printf("fdc reset\n");
843: #endif
844: }
845:
846: void
847: fd_set_motor(fdc)
848: struct fdc_softc *fdc;
849: {
850: struct fd_softc *fd;
851: u_char status;
852: int n;
853:
854: status = FDO_FRST | FDO_FDMAEN;
855: if ((fd = TAILQ_FIRST(&fdc->sc_drives)) != NULL)
856: status |= fd->sc_drive;
857:
858: for (n = 0; n < 4; n++)
859: if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
860: status |= FDO_MOEN(n);
861: bus_space_write_1(fdc->sc_bustag, fdc->sc_handle,
862: FDREG77_DOR, status);
863: }
864:
865: void
866: fd_motor_off(arg)
867: void *arg;
868: {
869: struct fd_softc *fd = arg;
870: int s;
871:
872: s = splbio();
873: fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
874: fd_set_motor((struct fdc_softc *)fd->sc_dv.dv_parent);
875: splx(s);
876: }
877:
878: void
879: fd_motor_on(arg)
880: void *arg;
881: {
882: struct fd_softc *fd = arg;
883: struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
884: int s;
885:
886: s = splbio();
887: fd->sc_flags &= ~FD_MOTOR_WAIT;
888: if (fd == TAILQ_FIRST(&fdc->sc_drives) && fdc->sc_state == MOTORWAIT)
889: (void) fdcstate(fdc);
890: splx(s);
891: }
892:
893: /*
894: * Get status bytes off the FDC after a command has finished
895: * Returns the number of status bytes read; -1 on error.
896: * The return value is also stored in `sc_nstat'.
897: */
898: int
899: fdcresult(fdc)
900: struct fdc_softc *fdc;
901: {
902: bus_space_tag_t t = fdc->sc_bustag;
903: bus_space_handle_t h = fdc->sc_handle;
904: int j, n = 0;
905:
906: for (j = 100000; j; j--) {
907: u_int8_t v = bus_space_read_1(t, h, FDREG77_MSR);
908: v &= (NE7_DIO | NE7_RQM | NE7_CB);
909: if (v == NE7_RQM)
910: return (fdc->sc_nstat = n);
911: if (v == (NE7_DIO | NE7_RQM | NE7_CB)) {
912: if (n >= sizeof(fdc->sc_status)) {
913: log(LOG_ERR, "fdcresult: overrun\n");
914: return (-1);
915: }
916: fdc->sc_status[n++] =
917: bus_space_read_1(t, h, FDREG77_FIFO);
918: } else
919: delay(1);
920: }
921:
922: log(LOG_ERR, "fdcresult: timeout\n");
923: return (fdc->sc_nstat = -1);
924: }
925:
926: /*
927: * Write a command byte to the FDC.
928: * Returns 0 on success; -1 on failure (i.e. timeout)
929: */
930: int
931: fdc_wrfifo(fdc, x)
932: struct fdc_softc *fdc;
933: u_int8_t x;
934: {
935: bus_space_tag_t t = fdc->sc_bustag;
936: bus_space_handle_t h = fdc->sc_handle;
937: int i;
938:
939: for (i = 100000; i-- != 0;) {
940: u_int8_t v = bus_space_read_1(t, h, FDREG77_MSR);
941: if ((v & (NE7_DIO|NE7_RQM)) == NE7_RQM) {
942: /* The chip is ready */
943: bus_space_write_1(t, h, FDREG77_FIFO, x);
944: return (0);
945: }
946: delay(1);
947: }
948: return (-1);
949: }
950:
951: int
952: fdc_diskchange(fdc)
953: struct fdc_softc *fdc;
954: {
955: bus_space_tag_t t = fdc->sc_bustag;
956: bus_space_handle_t h = fdc->sc_handle;
957:
958: u_int8_t v = bus_space_read_1(t, h, FDREG77_DIR);
959: return ((v & FDI_DCHG) != 0);
960: }
961:
962: int
963: fdopen(dev, flags, fmt, p)
964: dev_t dev;
965: int flags, fmt;
966: struct proc *p;
967: {
968: int unit, pmask;
969: struct fd_softc *fd;
970: struct fd_type *type;
971:
972: unit = FDUNIT(dev);
973: if (unit >= fd_cd.cd_ndevs)
974: return (ENXIO);
975: fd = fd_cd.cd_devs[unit];
976: if (fd == NULL)
977: return (ENXIO);
978: type = fd_dev_to_type(fd, dev);
979: if (type == NULL)
980: return (ENXIO);
981:
982: if ((fd->sc_flags & FD_OPEN) != 0 &&
983: fd->sc_type != type)
984: return (EBUSY);
985:
986: fd->sc_type = type;
987: fd->sc_cylin = -1;
988: fd->sc_flags |= FD_OPEN;
989:
990: /*
991: * Only update the disklabel if we're not open anywhere else.
992: */
993: if (fd->sc_dk.dk_openmask == 0)
994: fdgetdisklabel(dev);
995:
996: pmask = (1 << DISKPART(dev));
997:
998: switch (fmt) {
999: case S_IFCHR:
1000: fd->sc_dk.dk_copenmask |= pmask;
1001: break;
1002:
1003: case S_IFBLK:
1004: fd->sc_dk.dk_bopenmask |= pmask;
1005: break;
1006: }
1007: fd->sc_dk.dk_openmask =
1008: fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask;
1009:
1010: return (0);
1011: }
1012:
1013: int
1014: fdclose(dev, flags, fmt, p)
1015: dev_t dev;
1016: int flags, fmt;
1017: struct proc *p;
1018: {
1019: struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1020: int pmask = (1 << DISKPART(dev));
1021:
1022: fd->sc_flags &= ~FD_OPEN;
1023: fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
1024:
1025: switch (fmt) {
1026: case S_IFCHR:
1027: fd->sc_dk.dk_copenmask &= ~pmask;
1028: break;
1029:
1030: case S_IFBLK:
1031: fd->sc_dk.dk_bopenmask &= ~pmask;
1032: break;
1033: }
1034: fd->sc_dk.dk_openmask =
1035: fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask;
1036:
1037: return (0);
1038: }
1039:
1040: int
1041: fdread(dev, uio, flag)
1042: dev_t dev;
1043: struct uio *uio;
1044: int flag;
1045: {
1046:
1047: return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
1048: }
1049:
1050: int
1051: fdwrite(dev, uio, flag)
1052: dev_t dev;
1053: struct uio *uio;
1054: int flag;
1055: {
1056:
1057: return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
1058: }
1059:
1060: void
1061: fdcstart(fdc)
1062: struct fdc_softc *fdc;
1063: {
1064:
1065: #ifdef DIAGNOSTIC
1066: /* only got here if controller's drive queue was inactive; should
1067: be in idle state */
1068: if (fdc->sc_state != DEVIDLE) {
1069: printf("fdcstart: not idle\n");
1070: return;
1071: }
1072: #endif
1073: (void) fdcstate(fdc);
1074: }
1075:
1076: void
1077: fdcstatus(fdc, s)
1078: struct fdc_softc *fdc;
1079: char *s;
1080: {
1081: struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives);
1082: int n;
1083:
1084: /* Just print last status */
1085: n = fdc->sc_nstat;
1086:
1087: #if 0
1088: if (n == 0) {
1089: fdc_wrfifo(fdc, NE7CMD_SENSEI);
1090: (void) fdcresult(fdc);
1091: n = 2;
1092: }
1093: #endif
1094:
1095: printf("%s: %s: state %d",
1096: fd ? fd->sc_dv.dv_xname : "fdc", s, fdc->sc_state);
1097:
1098: switch (n) {
1099: case 0:
1100: printf("\n");
1101: break;
1102: case 2:
1103: printf(" (st0 %b cyl %d)\n",
1104: fdc->sc_status[0], NE7_ST0BITS,
1105: fdc->sc_status[1]);
1106: break;
1107: case 7:
1108: printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
1109: fdc->sc_status[0], NE7_ST0BITS,
1110: fdc->sc_status[1], NE7_ST1BITS,
1111: fdc->sc_status[2], NE7_ST2BITS,
1112: fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1113: break;
1114: #ifdef DIAGNOSTIC
1115: default:
1116: printf(" fdcstatus: weird size: %d\n", n);
1117: break;
1118: #endif
1119: }
1120: }
1121:
1122: void
1123: fdctimeout(arg)
1124: void *arg;
1125: {
1126: struct fdc_softc *fdc = arg;
1127: struct fd_softc *fd;
1128: int s;
1129:
1130: s = splbio();
1131: fd = TAILQ_FIRST(&fdc->sc_drives);
1132: if (fd == NULL) {
1133: printf("%s: timeout but no I/O pending: state %d, istatus=%d\n",
1134: fdc->sc_dev.dv_xname, fdc->sc_state, fdc->sc_istatus);
1135: fdc->sc_state = DEVIDLE;
1136: goto out;
1137: }
1138:
1139: if (fd->sc_q.b_actf)
1140: fdc->sc_state++;
1141: else
1142: fdc->sc_state = DEVIDLE;
1143:
1144: (void) fdcstate(fdc);
1145: out:
1146: splx(s);
1147:
1148: }
1149:
1150: void
1151: fdcpseudointr(arg)
1152: void *arg;
1153: {
1154: struct fdc_softc *fdc = arg;
1155: int s;
1156:
1157: /* Just ensure it has the right spl. */
1158: s = splbio();
1159: (void) fdcstate(fdc);
1160: splx(s);
1161: }
1162:
1163:
1164: /*
1165: * Hardware interrupt entry point.
1166: * Unfortunately, we have no reliable way to determine that the
1167: * interrupt really came from the floppy controller; just hope
1168: * that the other devices that share this interrupt can do better..
1169: */
1170: int
1171: fdchwintr(arg)
1172: void *arg;
1173: {
1174: struct fdc_softc *fdc = arg;
1175: bus_space_tag_t t = fdc->sc_bustag;
1176: bus_space_handle_t h = fdc->sc_handle;
1177:
1178: switch (fdc->sc_itask) {
1179: case FDC_ITASK_NONE:
1180: return (0);
1181: case FDC_ITASK_SENSEI:
1182: if (fdc_wrfifo(fdc, NE7CMD_SENSEI) != 0 || fdcresult(fdc) == -1)
1183: fdc->sc_istatus = FDC_ISTATUS_ERROR;
1184: else
1185: fdc->sc_istatus = FDC_ISTATUS_DONE;
1186: softintr_schedule(fdc->sc_sicookie);
1187: return (1);
1188: case FDC_ITASK_RESULT:
1189: if (fdcresult(fdc) == -1)
1190: fdc->sc_istatus = FDC_ISTATUS_ERROR;
1191: else
1192: fdc->sc_istatus = FDC_ISTATUS_DONE;
1193: softintr_schedule(fdc->sc_sicookie);
1194: return (1);
1195: case FDC_ITASK_DMA:
1196: /* Proceed with pseudo-DMA below */
1197: break;
1198: default:
1199: printf("fdc: stray hard interrupt: itask=%d\n", fdc->sc_itask);
1200: fdc->sc_istatus = FDC_ISTATUS_SPURIOUS;
1201: softintr_schedule(fdc->sc_sicookie);
1202: return (1);
1203: }
1204:
1205: /*
1206: * Pseudo DMA in progress
1207: */
1208: for (;;) {
1209: u_int8_t msr;
1210:
1211: msr = bus_space_read_1(t, h, FDREG77_MSR);
1212:
1213: if ((msr & NE7_RQM) == 0)
1214: /* That's all this round */
1215: break;
1216:
1217: if ((msr & NE7_NDM) == 0) {
1218: fdcresult(fdc);
1219: fdc->sc_istatus = FDC_ISTATUS_DONE;
1220: softintr_schedule(fdc->sc_sicookie);
1221: #ifdef FD_DEBUG
1222: if (fdc_debug > 1)
1223: printf("fdc: overrun: msr = %x, tc = %d\n",
1224: msr, fdc->sc_tc);
1225: #endif
1226: break;
1227: }
1228:
1229: /* Another byte can be transferred */
1230: if ((msr & NE7_DIO) != 0)
1231: *fdc->sc_data =
1232: bus_space_read_1(t, h, FDREG77_FIFO);
1233: else
1234: bus_space_write_1(t, h, FDREG77_FIFO,
1235: *fdc->sc_data);
1236:
1237: fdc->sc_data++;
1238: if (--fdc->sc_tc == 0) {
1239: fdc->sc_istatus = FDC_ISTATUS_DONE;
1240: FTC_FLIP;
1241: fdcresult(fdc);
1242: softintr_schedule(fdc->sc_sicookie);
1243: break;
1244: }
1245: }
1246: return (1);
1247: }
1248:
1249: void
1250: fdcswintr(arg)
1251: void *arg;
1252: {
1253: struct fdc_softc *fdc = arg;
1254: int s;
1255:
1256: if (fdc->sc_istatus == FDC_ISTATUS_NONE)
1257: /* This (software) interrupt is not for us */
1258: return;
1259:
1260: switch (fdc->sc_istatus) {
1261: case FDC_ISTATUS_ERROR:
1262: printf("fdc: ierror status: state %d\n", fdc->sc_state);
1263: break;
1264: case FDC_ISTATUS_SPURIOUS:
1265: printf("fdc: spurious interrupt: state %d\n", fdc->sc_state);
1266: break;
1267: }
1268:
1269: s = splbio();
1270: fdcstate(fdc);
1271: splx(s);
1272: return;
1273: }
1274:
1275: int
1276: fdcstate(fdc)
1277: struct fdc_softc *fdc;
1278: {
1279: #define st0 fdc->sc_status[0]
1280: #define st1 fdc->sc_status[1]
1281: #define cyl fdc->sc_status[1]
1282: #define FDC_WRFIFO(fdc, c) \
1283: do { \
1284: if (fdc_wrfifo(fdc, (c))) { \
1285: goto xxx; \
1286: } \
1287: } while(0)
1288:
1289: struct fd_softc *fd;
1290: struct buf *bp;
1291: int read, head, sec, nblks;
1292: struct fd_type *type;
1293: struct fd_formb *finfo = NULL;
1294:
1295: if (fdc->sc_istatus == FDC_ISTATUS_ERROR) {
1296: /* Prevent loop if the reset sequence produces errors */
1297: if (fdc->sc_state != RESETCOMPLETE &&
1298: fdc->sc_state != RECALWAIT &&
1299: fdc->sc_state != RECALCOMPLETE)
1300: fdc->sc_state = DORESET;
1301: }
1302:
1303: /* Clear I task/status field */
1304: fdc->sc_istatus = FDC_ISTATUS_NONE;
1305: fdc->sc_itask = FDC_ITASK_NONE;
1306:
1307: loop:
1308: /* Is there a drive for the controller to do a transfer with? */
1309: fd = TAILQ_FIRST(&fdc->sc_drives);
1310: if (fd == NULL) {
1311: fdc->sc_state = DEVIDLE;
1312: return (0);
1313: }
1314:
1315: /* Is there a transfer to this drive? If not, deactivate drive. */
1316: bp = fd->sc_q.b_actf;
1317: if (bp == NULL) {
1318: fd->sc_ops = 0;
1319: TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1320: fd->sc_q.b_active = 0;
1321: goto loop;
1322: }
1323:
1324: if (bp->b_flags & B_FORMAT)
1325: finfo = (struct fd_formb *)bp->b_data;
1326:
1327: switch (fdc->sc_state) {
1328: case DEVIDLE:
1329: fdc->sc_errors = 0;
1330: fd->sc_skip = 0;
1331: fd->sc_bcount = bp->b_bcount;
1332: fd->sc_blkno = (bp->b_blkno * DEV_BSIZE) / FD_BSIZE(fd);
1333: timeout_del(&fd->sc_motoroff_to);
1334: if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1335: fdc->sc_state = MOTORWAIT;
1336: return (1);
1337: }
1338: if ((fd->sc_flags & FD_MOTOR) == 0) {
1339: /* Turn on the motor, being careful about pairing. */
1340: struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
1341: if (ofd && ofd->sc_flags & FD_MOTOR) {
1342: timeout_del(&ofd->sc_motoroff_to);
1343: ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1344: }
1345: fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1346: fd_set_motor(fdc);
1347: fdc->sc_state = MOTORWAIT;
1348: if ((fdc->sc_flags & FDC_NEEDMOTORWAIT) != 0) { /*XXX*/
1349: /* Allow .25s for motor to stabilize. */
1350: timeout_add(&fd->sc_motoron_to, hz / 4);
1351: } else {
1352: fd->sc_flags &= ~FD_MOTOR_WAIT;
1353: goto loop;
1354: }
1355: return (1);
1356: }
1357: /* Make sure the right drive is selected. */
1358: fd_set_motor(fdc);
1359:
1360: if (fdc_diskchange(fdc))
1361: goto dodskchg;
1362:
1363: /*FALLTHROUGH*/
1364: case DOSEEK:
1365: doseek:
1366: if ((fdc->sc_flags & FDC_EIS) &&
1367: (bp->b_flags & B_FORMAT) == 0) {
1368: fd->sc_cylin = bp->b_cylinder;
1369: /* We use implied seek */
1370: goto doio;
1371: }
1372:
1373: if (fd->sc_cylin == bp->b_cylinder)
1374: goto doio;
1375:
1376: fd->sc_cylin = -1;
1377: fdc->sc_state = SEEKWAIT;
1378: fdc->sc_nstat = 0;
1379:
1380: fd->sc_dk.dk_seek++;
1381:
1382: disk_busy(&fd->sc_dk);
1383: timeout_add(&fdc->fdctimeout_to, 4 * hz);
1384:
1385: /* specify command */
1386: FDC_WRFIFO(fdc, NE7CMD_SPECIFY);
1387: FDC_WRFIFO(fdc, fd->sc_type->steprate);
1388: /* XXX head load time == 6ms */
1389: FDC_WRFIFO(fdc, 6 | NE7_SPECIFY_NODMA);
1390:
1391: fdc->sc_itask = FDC_ITASK_SENSEI;
1392: /* seek function */
1393: FDC_WRFIFO(fdc, NE7CMD_SEEK);
1394: FDC_WRFIFO(fdc, fd->sc_drive); /* drive number */
1395: FDC_WRFIFO(fdc, bp->b_cylinder * fd->sc_type->step);
1396: return (1);
1397:
1398: case DODSKCHG:
1399: dodskchg:
1400: /*
1401: * Disk change: force a seek operation by going to cyl 1
1402: * followed by a recalibrate.
1403: */
1404: disk_busy(&fd->sc_dk);
1405: timeout_add(&fdc->fdctimeout_to, 4 * hz);
1406: fd->sc_cylin = -1;
1407: fdc->sc_nstat = 0;
1408: fdc->sc_state = DSKCHGWAIT;
1409:
1410: fdc->sc_itask = FDC_ITASK_SENSEI;
1411: /* seek function */
1412: FDC_WRFIFO(fdc, NE7CMD_SEEK);
1413: FDC_WRFIFO(fdc, fd->sc_drive); /* drive number */
1414: FDC_WRFIFO(fdc, 1 * fd->sc_type->step);
1415: return (1);
1416:
1417: case DSKCHGWAIT:
1418: timeout_del(&fdc->fdctimeout_to);
1419: disk_unbusy(&fd->sc_dk, 0, 0);
1420: if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 ||
1421: cyl != 1 * fd->sc_type->step) {
1422: fdcstatus(fdc, "dskchg seek failed");
1423: fdc->sc_state = DORESET;
1424: } else
1425: fdc->sc_state = DORECAL;
1426:
1427: if (fdc_diskchange(fdc)) {
1428: printf("%s: cannot clear disk change status\n",
1429: fdc->sc_dev.dv_xname);
1430: fdc->sc_state = DORESET;
1431: }
1432: goto loop;
1433:
1434: case DOIO:
1435: doio:
1436: if (finfo != NULL)
1437: fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1438: (char *)finfo;
1439: type = fd->sc_type;
1440: sec = fd->sc_blkno % type->seccyl;
1441: nblks = type->seccyl - sec;
1442: nblks = min(nblks, fd->sc_bcount / FD_BSIZE(fd));
1443: nblks = min(nblks, FDC_MAXIOSIZE / FD_BSIZE(fd));
1444: fd->sc_nblks = nblks;
1445: fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FD_BSIZE(fd);
1446: head = sec / type->sectrac;
1447: sec -= head * type->sectrac;
1448: #ifdef DIAGNOSTIC
1449: {
1450: daddr64_t block;
1451:
1452: block = (fd->sc_cylin * type->heads + head) *
1453: type->sectrac + sec;
1454: if (block != fd->sc_blkno) {
1455: printf("fdcintr: block %lld != blkno %d\n",
1456: block, (int)fd->sc_blkno);
1457: #if defined(FD_DEBUG) && defined(DDB)
1458: Debugger();
1459: #endif
1460: }
1461: }
1462: #endif
1463: read = bp->b_flags & B_READ;
1464:
1465: /* Setup for pseudo DMA */
1466: fdc->sc_data = bp->b_data + fd->sc_skip;
1467: fdc->sc_tc = fd->sc_nbytes;
1468:
1469: bus_space_write_1(fdc->sc_bustag, fdc->sc_handle,
1470: FDREG77_DRS, type->rate);
1471: #ifdef FD_DEBUG
1472: if (fdc_debug > 1)
1473: printf("fdcstate: doio: %s drive %d "
1474: "track %d head %d sec %d nblks %d\n",
1475: finfo ? "format" :
1476: (read ? "read" : "write"),
1477: fd->sc_drive, fd->sc_cylin, head, sec, nblks);
1478: #endif
1479: fdc->sc_state = IOCOMPLETE;
1480: fdc->sc_itask = FDC_ITASK_DMA;
1481: fdc->sc_nstat = 0;
1482:
1483: disk_busy(&fd->sc_dk);
1484:
1485: /* allow 3 seconds for operation */
1486: timeout_add(&fdc->fdctimeout_to, 3 * hz);
1487:
1488: if (finfo != NULL) {
1489: /* formatting */
1490: FDC_WRFIFO(fdc, NE7CMD_FORMAT);
1491: FDC_WRFIFO(fdc, (head << 2) | fd->sc_drive);
1492: FDC_WRFIFO(fdc, finfo->fd_formb_secshift);
1493: FDC_WRFIFO(fdc, finfo->fd_formb_nsecs);
1494: FDC_WRFIFO(fdc, finfo->fd_formb_gaplen);
1495: FDC_WRFIFO(fdc, finfo->fd_formb_fillbyte);
1496: } else {
1497: if (read)
1498: FDC_WRFIFO(fdc, NE7CMD_READ);
1499: else
1500: FDC_WRFIFO(fdc, NE7CMD_WRITE);
1501: FDC_WRFIFO(fdc, (head << 2) | fd->sc_drive);
1502: FDC_WRFIFO(fdc, fd->sc_cylin); /*track*/
1503: FDC_WRFIFO(fdc, head);
1504: FDC_WRFIFO(fdc, sec + 1); /*sector+1*/
1505: FDC_WRFIFO(fdc, type->secsize); /*sector size*/
1506: FDC_WRFIFO(fdc, type->sectrac); /*secs/track*/
1507: FDC_WRFIFO(fdc, type->gap1); /*gap1 size*/
1508: FDC_WRFIFO(fdc, type->datalen); /*data length*/
1509: }
1510:
1511: return (1); /* will return later */
1512:
1513: case SEEKWAIT:
1514: timeout_del(&fdc->fdctimeout_to);
1515: fdc->sc_state = SEEKCOMPLETE;
1516: if (fdc->sc_flags & FDC_NEEDHEADSETTLE) {
1517: /* allow 1/50 second for heads to settle */
1518: timeout_add(&fdc->fdcpseudointr_to, hz / 50);
1519: return (1); /* will return later */
1520: }
1521: /*FALLTHROUGH*/
1522: case SEEKCOMPLETE:
1523: /* no data on seek */
1524: disk_unbusy(&fd->sc_dk, 0, 0);
1525:
1526: /* Make sure seek really happened. */
1527: if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 ||
1528: cyl != bp->b_cylinder * fd->sc_type->step) {
1529: #ifdef FD_DEBUG
1530: if (fdc_debug)
1531: fdcstatus(fdc, "seek failed");
1532: #endif
1533: fdcretry(fdc);
1534: goto loop;
1535: }
1536: fd->sc_cylin = bp->b_cylinder;
1537: goto doio;
1538:
1539: case IOTIMEDOUT:
1540: /*
1541: * Try to abort the I/O operation without resetting
1542: * the chip first. Poke TC and arrange to pick up
1543: * the timed out I/O command's status.
1544: */
1545: fdc->sc_itask = FDC_ITASK_RESULT;
1546: fdc->sc_state = IOCLEANUPWAIT;
1547: fdc->sc_nstat = 0;
1548: /* 1/10 second should be enough */
1549: timeout_add(&fdc->fdctimeout_to, hz / 10);
1550: return (1);
1551:
1552: case IOCLEANUPTIMEDOUT:
1553: case SEEKTIMEDOUT:
1554: case RECALTIMEDOUT:
1555: case RESETTIMEDOUT:
1556: case DSKCHGTIMEDOUT:
1557: fdcstatus(fdc, "timeout");
1558:
1559: /* All other timeouts always roll through to a chip reset */
1560: fdcretry(fdc);
1561:
1562: /* Force reset, no matter what fdcretry() says */
1563: fdc->sc_state = DORESET;
1564: goto loop;
1565:
1566: case IOCLEANUPWAIT: /* IO FAILED, cleanup succeeded */
1567: timeout_del(&fdc->fdctimeout_to);
1568: disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
1569: (bp->b_flags & B_READ));
1570: fdcretry(fdc);
1571: goto loop;
1572:
1573: case IOCOMPLETE: /* IO DONE, post-analyze */
1574: timeout_del(&fdc->fdctimeout_to);
1575:
1576: disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
1577: (bp->b_flags & B_READ));
1578:
1579: if (fdc->sc_nstat != 7 || st1 != 0 ||
1580: ((st0 & 0xf8) != 0 &&
1581: ((st0 & 0xf8) != 0x20 || (fdc->sc_cfg & CFG_EIS) == 0))) {
1582: #ifdef FD_DEBUG
1583: if (fdc_debug) {
1584: fdcstatus(fdc,
1585: bp->b_flags & B_READ
1586: ? "read failed" : "write failed");
1587: printf("blkno %lld nblks %d nstat %d tc %d\n",
1588: fd->sc_blkno, fd->sc_nblks,
1589: fdc->sc_nstat, fdc->sc_tc);
1590: }
1591: #endif
1592: if (fdc->sc_nstat == 7 &&
1593: (st1 & ST1_OVERRUN) == ST1_OVERRUN) {
1594:
1595: /*
1596: * Silently retry overruns if no other
1597: * error bit is set. Adjust threshold.
1598: */
1599: int thr = fdc->sc_cfg & CFG_THRHLD_MASK;
1600: if (thr < 15) {
1601: thr++;
1602: fdc->sc_cfg &= ~CFG_THRHLD_MASK;
1603: fdc->sc_cfg |= (thr & CFG_THRHLD_MASK);
1604: #ifdef FD_DEBUG
1605: if (fdc_debug)
1606: printf("fdc: %d -> threshold\n", thr);
1607: #endif
1608: fdconf(fdc);
1609: fdc->sc_overruns = 0;
1610: }
1611: if (++fdc->sc_overruns < 3) {
1612: fdc->sc_state = DOIO;
1613: goto loop;
1614: }
1615: }
1616: fdcretry(fdc);
1617: goto loop;
1618: }
1619: if (fdc->sc_errors) {
1620: diskerr(bp, "fd", "soft error", LOG_PRINTF,
1621: fd->sc_skip / FD_BSIZE(fd),
1622: (struct disklabel *)NULL);
1623: printf("\n");
1624: fdc->sc_errors = 0;
1625: } else {
1626: if (--fdc->sc_overruns < -20) {
1627: int thr = fdc->sc_cfg & CFG_THRHLD_MASK;
1628: if (thr > 0) {
1629: thr--;
1630: fdc->sc_cfg &= ~CFG_THRHLD_MASK;
1631: fdc->sc_cfg |= (thr & CFG_THRHLD_MASK);
1632: #ifdef FD_DEBUG
1633: if (fdc_debug)
1634: printf("fdc: %d -> threshold\n", thr);
1635: #endif
1636: fdconf(fdc);
1637: }
1638: fdc->sc_overruns = 0;
1639: }
1640: }
1641: fd->sc_blkno += fd->sc_nblks;
1642: fd->sc_skip += fd->sc_nbytes;
1643: fd->sc_bcount -= fd->sc_nbytes;
1644: if (finfo == NULL && fd->sc_bcount > 0) {
1645: bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1646: goto doseek;
1647: }
1648: fdfinish(fd, bp);
1649: goto loop;
1650:
1651: case DORESET:
1652: /* try a reset, keep motor on */
1653: fd_set_motor(fdc);
1654: delay(100);
1655: fdc->sc_nstat = 0;
1656: fdc->sc_itask = FDC_ITASK_SENSEI;
1657: fdc->sc_state = RESETCOMPLETE;
1658: timeout_add(&fdc->fdctimeout_to, hz / 2);
1659: fdc_reset(fdc);
1660: return (1); /* will return later */
1661:
1662: case RESETCOMPLETE:
1663: timeout_del(&fdc->fdctimeout_to);
1664: fdconf(fdc);
1665:
1666: /* FALLTHROUGH */
1667: case DORECAL:
1668: fdc->sc_state = RECALWAIT;
1669: fdc->sc_itask = FDC_ITASK_SENSEI;
1670: fdc->sc_nstat = 0;
1671: timeout_add(&fdc->fdctimeout_to, 5 * hz);
1672: /* recalibrate function */
1673: FDC_WRFIFO(fdc, NE7CMD_RECAL);
1674: FDC_WRFIFO(fdc, fd->sc_drive);
1675: return (1); /* will return later */
1676:
1677: case RECALWAIT:
1678: timeout_del(&fdc->fdctimeout_to);
1679: fdc->sc_state = RECALCOMPLETE;
1680: if (fdc->sc_flags & FDC_NEEDHEADSETTLE) {
1681: /* allow 1/30 second for heads to settle */
1682: timeout_add(&fdc->fdcpseudointr_to, hz / 30);
1683: return (1); /* will return later */
1684: }
1685:
1686: case RECALCOMPLETE:
1687: if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1688: #ifdef FD_DEBUG
1689: if (fdc_debug)
1690: fdcstatus(fdc, "recalibrate failed");
1691: #endif
1692: fdcretry(fdc);
1693: goto loop;
1694: }
1695: fd->sc_cylin = 0;
1696: goto doseek;
1697:
1698: case MOTORWAIT:
1699: if (fd->sc_flags & FD_MOTOR_WAIT)
1700: return (1); /* time's not up yet */
1701: goto doseek;
1702:
1703: default:
1704: fdcstatus(fdc, "stray interrupt");
1705: return (1);
1706: }
1707: #ifdef DIAGNOSTIC
1708: panic("fdcintr: impossible");
1709: #endif
1710:
1711: xxx:
1712: /*
1713: * We get here if the chip locks up in FDC_WRFIFO()
1714: * Cancel any operation and schedule a reset
1715: */
1716: timeout_del(&fdc->fdctimeout_to);
1717: fdcretry(fdc);
1718: fdc->sc_state = DORESET;
1719: goto loop;
1720:
1721: #undef st0
1722: #undef st1
1723: #undef cyl
1724: }
1725:
1726: void
1727: fdcretry(fdc)
1728: struct fdc_softc *fdc;
1729: {
1730: struct fd_softc *fd;
1731: struct buf *bp;
1732: int error = EIO;
1733:
1734: fd = TAILQ_FIRST(&fdc->sc_drives);
1735: bp = fd->sc_q.b_actf;
1736:
1737: fdc->sc_overruns = 0;
1738: if (fd->sc_opts & FDOPT_NORETRY)
1739: goto fail;
1740:
1741: switch (fdc->sc_errors) {
1742: case 0:
1743: if (fdc->sc_nstat == 7 &&
1744: (fdc->sc_status[0] & 0xd8) == 0x40 &&
1745: (fdc->sc_status[1] & 0x2) == 0x2) {
1746: printf("%s: read-only medium\n", fd->sc_dv.dv_xname);
1747: error = EROFS;
1748: goto failsilent;
1749: }
1750: /* try again */
1751: fdc->sc_state =
1752: (fdc->sc_flags & FDC_EIS) ? DOIO : DOSEEK;
1753: break;
1754:
1755: case 1: case 2: case 3:
1756: /* didn't work; try recalibrating */
1757: fdc->sc_state = DORECAL;
1758: break;
1759:
1760: case 4:
1761: if (fdc->sc_nstat == 7 &&
1762: fdc->sc_status[0] == 0 &&
1763: fdc->sc_status[1] == 0 &&
1764: fdc->sc_status[2] == 0) {
1765: /*
1766: * We've retried a few times and we've got
1767: * valid status and all three status bytes
1768: * are zero. Assume this condition is the
1769: * result of no disk loaded into the drive.
1770: */
1771: printf("%s: no medium?\n", fd->sc_dv.dv_xname);
1772: error = ENODEV;
1773: goto failsilent;
1774: }
1775:
1776: /* still no go; reset the bastard */
1777: fdc->sc_state = DORESET;
1778: break;
1779:
1780: default:
1781: fail:
1782: if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1783: diskerr(bp, "fd", "hard error", LOG_PRINTF,
1784: fd->sc_skip / FD_BSIZE(fd),
1785: (struct disklabel *)NULL);
1786: printf("\n");
1787: fdcstatus(fdc, "controller status");
1788: }
1789:
1790: failsilent:
1791: bp->b_flags |= B_ERROR;
1792: bp->b_error = error;
1793: fdfinish(fd, bp);
1794: }
1795: fdc->sc_errors++;
1796: }
1797:
1798: daddr64_t
1799: fdsize(dev)
1800: dev_t dev;
1801: {
1802:
1803: /* Swapping to floppies would not make sense. */
1804: return (-1);
1805: }
1806:
1807: int
1808: fddump(dev, blkno, va, size)
1809: dev_t dev;
1810: daddr64_t blkno;
1811: caddr_t va;
1812: size_t size;
1813: {
1814:
1815: /* Not implemented. */
1816: return (EINVAL);
1817: }
1818:
1819: int
1820: fdioctl(dev, cmd, addr, flag, p)
1821: dev_t dev;
1822: u_long cmd;
1823: caddr_t addr;
1824: int flag;
1825: struct proc *p;
1826: {
1827: struct fd_softc *fd;
1828: struct fdc_softc *fdc;
1829: int unit;
1830: int error;
1831: #ifdef FD_DEBUG
1832: int i;
1833: #endif
1834:
1835: unit = FDUNIT(dev);
1836: if (unit >= fd_cd.cd_ndevs)
1837: return (ENXIO);
1838:
1839: fd = fd_cd.cd_devs[FDUNIT(dev)];
1840: fdc = (struct fdc_softc *)fd->sc_dv.dv_parent;
1841:
1842: switch (cmd) {
1843: case DIOCGDINFO:
1844: *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1845: return 0;
1846:
1847: case DIOCWLABEL:
1848: if ((flag & FWRITE) == 0)
1849: return EBADF;
1850: /* XXX do something */
1851: return (0);
1852:
1853: case DIOCWDINFO:
1854: if ((flag & FWRITE) == 0)
1855: return (EBADF);
1856:
1857: error = setdisklabel(fd->sc_dk.dk_label,
1858: (struct disklabel *)addr, 0);
1859: if (error)
1860: return (error);
1861:
1862: error = writedisklabel(DISKLABELDEV(dev), fdstrategy,
1863: fd->sc_dk.dk_label);
1864: return (error);
1865:
1866: case DIOCLOCK:
1867: /*
1868: * Nothing to do here, really.
1869: */
1870: return (0);
1871:
1872: case MTIOCTOP:
1873: if (((struct mtop *)addr)->mt_op != MTOFFL)
1874: return (EIO);
1875: /* FALLTHROUGH */
1876: case DIOCEJECT:
1877: if (fdc->sc_flags & FDC_NOEJECT)
1878: return (ENODEV);
1879: fd_do_eject(fd);
1880: return (0);
1881:
1882: case FD_FORM:
1883: if ((flag & FWRITE) == 0)
1884: return (EBADF); /* must be opened for writing */
1885: else if (((struct fd_formb *)addr)->format_version !=
1886: FD_FORMAT_VERSION)
1887: return (EINVAL);/* wrong version of formatting prog */
1888: else
1889: return fdformat(dev, (struct fd_formb *)addr, p);
1890: break;
1891:
1892: case FD_GTYPE: /* get drive options */
1893: *(struct fd_type *)addr = *fd->sc_type;
1894: return (0);
1895:
1896: case FD_GOPTS: /* get drive options */
1897: *(int *)addr = fd->sc_opts;
1898: return (0);
1899:
1900: case FD_SOPTS: /* set drive options */
1901: fd->sc_opts = *(int *)addr;
1902: return (0);
1903:
1904: #ifdef FD_DEBUG
1905: case _IO('f', 100):
1906: fdc_wrfifo(fdc, NE7CMD_DUMPREG);
1907: fdcresult(fdc);
1908: printf("fdc: dumpreg(%d regs): <", fdc->sc_nstat);
1909: for (i = 0; i < fdc->sc_nstat; i++)
1910: printf(" 0x%x", fdc->sc_status[i]);
1911: printf(">\n");
1912: return (0);
1913:
1914: case _IOW('f', 101, int):
1915: fdc->sc_cfg &= ~CFG_THRHLD_MASK;
1916: fdc->sc_cfg |= (*(int *)addr & CFG_THRHLD_MASK);
1917: fdconf(fdc);
1918: return (0);
1919:
1920: case _IO('f', 102):
1921: fdc_wrfifo(fdc, NE7CMD_SENSEI);
1922: fdcresult(fdc);
1923: printf("fdc: sensei(%d regs): <", fdc->sc_nstat);
1924: for (i=0; i< fdc->sc_nstat; i++)
1925: printf(" 0x%x", fdc->sc_status[i]);
1926: printf(">\n");
1927: return (0);
1928: #endif
1929: default:
1930: return (ENOTTY);
1931: }
1932: }
1933:
1934: int
1935: fdformat(dev, finfo, p)
1936: dev_t dev;
1937: struct fd_formb *finfo;
1938: struct proc *p;
1939: {
1940: int rv = 0;
1941: struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1942: struct fd_type *type = fd->sc_type;
1943: struct buf *bp;
1944:
1945: /* set up a buffer header for fdstrategy() */
1946: bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1947: if (bp == NULL)
1948: return (ENOBUFS);
1949:
1950: bzero((void *)bp, sizeof(struct buf));
1951: bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1952: bp->b_proc = p;
1953: bp->b_dev = dev;
1954:
1955: /*
1956: * Calculate a fake blkno, so fdstrategy() would initiate a
1957: * seek to the requested cylinder.
1958: */
1959: bp->b_blkno = ((finfo->cyl * (type->sectrac * type->heads)
1960: + finfo->head * type->sectrac) * FD_BSIZE(fd))
1961: / DEV_BSIZE;
1962:
1963: bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1964: bp->b_data = (caddr_t)finfo;
1965:
1966: #ifdef FD_DEBUG
1967: if (fdc_debug) {
1968: int i;
1969:
1970: printf("fdformat: blkno 0x%llx count %ld\n",
1971: (unsigned long long)bp->b_blkno, bp->b_bcount);
1972:
1973: printf("\tcyl:\t%d\n", finfo->cyl);
1974: printf("\thead:\t%d\n", finfo->head);
1975: printf("\tnsecs:\t%d\n", finfo->fd_formb_nsecs);
1976: printf("\tsshft:\t%d\n", finfo->fd_formb_secshift);
1977: printf("\tgaplen:\t%d\n", finfo->fd_formb_gaplen);
1978: printf("\ttrack data:");
1979: for (i = 0; i < finfo->fd_formb_nsecs; i++) {
1980: printf(" [c%d h%d s%d]",
1981: finfo->fd_formb_cylno(i),
1982: finfo->fd_formb_headno(i),
1983: finfo->fd_formb_secno(i) );
1984: if (finfo->fd_formb_secsize(i) != 2)
1985: printf("<sz:%d>", finfo->fd_formb_secsize(i));
1986: }
1987: printf("\n");
1988: }
1989: #endif
1990:
1991: /* now do the format */
1992: fdstrategy(bp);
1993:
1994: /* ...and wait for it to complete */
1995: rv = biowait(bp);
1996: free(bp, M_TEMP);
1997: return (rv);
1998: }
1999:
2000: void
2001: fdgetdisklabel(dev)
2002: dev_t dev;
2003: {
2004: int unit = FDUNIT(dev);
2005: struct fd_softc *fd = fd_cd.cd_devs[unit];
2006: struct disklabel *lp = fd->sc_dk.dk_label;
2007: char *errstring;
2008:
2009: bzero(lp, sizeof(struct disklabel));
2010:
2011: lp->d_type = DTYPE_FLOPPY;
2012: lp->d_secsize = FD_BSIZE(fd);
2013: lp->d_secpercyl = fd->sc_type->seccyl;
2014: lp->d_nsectors = fd->sc_type->sectrac;
2015: lp->d_ncylinders = fd->sc_type->tracks;
2016: lp->d_ntracks = fd->sc_type->heads; /* Go figure... */
2017: DL_SETDSIZE(lp, (daddr64_t)lp->d_secpercyl * lp->d_ncylinders);
2018: lp->d_rpm = 300; /* XXX like it matters... */
2019:
2020: strncpy(lp->d_typename, "floppy disk", sizeof(lp->d_typename));
2021: strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
2022: lp->d_interleave = 1;
2023: lp->d_version = 1;
2024:
2025: lp->d_magic = DISKMAGIC;
2026: lp->d_magic2 = DISKMAGIC;
2027: lp->d_checksum = dkcksum(lp);
2028:
2029: /*
2030: * Call the generic disklabel extraction routine. If there's
2031: * not a label there, fake it.
2032: */
2033: errstring = readdisklabel(DISKLABELDEV(dev), fdstrategy, lp, 0);
2034: if (errstring) {
2035: /*printf("%s: %s\n", fd->sc_dv.dv_xname, errstring);*/
2036: }
2037: }
2038:
2039: void
2040: fd_do_eject(fd)
2041: struct fd_softc *fd;
2042: {
2043: struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
2044: bus_space_tag_t t = fdc->sc_bustag;
2045: bus_space_handle_t h = fdc->sc_handle;
2046: u_int8_t dor = FDO_FRST | FDO_FDMAEN | FDO_MOEN(0);
2047:
2048: bus_space_write_1(t, h, FDREG77_DOR, dor | FDO_EJ);
2049: delay(10);
2050: bus_space_write_1(t, h, FDREG77_DOR, FDO_FRST | FDO_DS);
2051: }
CVSweb