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