Deleted Added
full compact
fdc.c (58934) fdc.c (59249)
1/*
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Don Ahn.
7 *
8 * Libretto PCMCIA floppy support by David Horwitt (dhorwitt@ucsd.edu)
9 * aided by the Linux floppy driver modifications from David Bateman
10 * (dbateman@eng.uts.edu.au).
11 *
12 * Copyright (c) 1993, 1994 by
13 * jc@irbs.UUCP (John Capo)
14 * vak@zebub.msk.su (Serge Vakulenko)
15 * ache@astral.msk.su (Andrew A. Chernov)
16 *
17 * Copyright (c) 1993, 1994, 1995 by
18 * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
19 * dufault@hda.com (Peter Dufault)
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
23 * are met:
24 * 1. Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 * 3. All advertising materials mentioning features or use of this software
30 * must display the following acknowledgement:
31 * This product includes software developed by the University of
32 * California, Berkeley and its contributors.
33 * 4. Neither the name of the University nor the names of its contributors
34 * may be used to endorse or promote products derived from this software
35 * without specific prior written permission.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 *
49 * from: @(#)fd.c 7.4 (Berkeley) 5/25/91
1/*
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Don Ahn.
7 *
8 * Libretto PCMCIA floppy support by David Horwitt (dhorwitt@ucsd.edu)
9 * aided by the Linux floppy driver modifications from David Bateman
10 * (dbateman@eng.uts.edu.au).
11 *
12 * Copyright (c) 1993, 1994 by
13 * jc@irbs.UUCP (John Capo)
14 * vak@zebub.msk.su (Serge Vakulenko)
15 * ache@astral.msk.su (Andrew A. Chernov)
16 *
17 * Copyright (c) 1993, 1994, 1995 by
18 * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
19 * dufault@hda.com (Peter Dufault)
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
23 * are met:
24 * 1. Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 * 3. All advertising materials mentioning features or use of this software
30 * must display the following acknowledgement:
31 * This product includes software developed by the University of
32 * California, Berkeley and its contributors.
33 * 4. Neither the name of the University nor the names of its contributors
34 * may be used to endorse or promote products derived from this software
35 * without specific prior written permission.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 *
49 * from: @(#)fd.c 7.4 (Berkeley) 5/25/91
50 * $FreeBSD: head/sys/dev/fdc/fdc.c 58934 2000-04-02 15:24:56Z phk $
50 * $FreeBSD: head/sys/dev/fdc/fdc.c 59249 2000-04-15 05:54:02Z phk $
51 *
52 */
53
54#include "opt_fdc.h"
55#include "card.h"
56
57#include <sys/param.h>
58#include <sys/systm.h>
59#include <sys/kernel.h>
60#include <sys/buf.h>
61#include <sys/bus.h>
62#include <sys/conf.h>
63#include <sys/disklabel.h>
64#include <sys/devicestat.h>
65#include <sys/fcntl.h>
66#include <sys/malloc.h>
67#include <sys/module.h>
68#include <sys/proc.h>
69#include <sys/syslog.h>
70
71#include <sys/bus.h>
72#include <machine/bus.h>
73#include <sys/rman.h>
74
75#include <machine/clock.h>
76#include <machine/ioctl_fd.h>
77#include <machine/resource.h>
78#include <machine/stdarg.h>
79
80#include <isa/isavar.h>
81#include <isa/isareg.h>
82#include <isa/fdreg.h>
83#include <isa/fdc.h>
84#include <isa/rtc.h>
85
86/* misuse a flag to identify format operation */
51 *
52 */
53
54#include "opt_fdc.h"
55#include "card.h"
56
57#include <sys/param.h>
58#include <sys/systm.h>
59#include <sys/kernel.h>
60#include <sys/buf.h>
61#include <sys/bus.h>
62#include <sys/conf.h>
63#include <sys/disklabel.h>
64#include <sys/devicestat.h>
65#include <sys/fcntl.h>
66#include <sys/malloc.h>
67#include <sys/module.h>
68#include <sys/proc.h>
69#include <sys/syslog.h>
70
71#include <sys/bus.h>
72#include <machine/bus.h>
73#include <sys/rman.h>
74
75#include <machine/clock.h>
76#include <machine/ioctl_fd.h>
77#include <machine/resource.h>
78#include <machine/stdarg.h>
79
80#include <isa/isavar.h>
81#include <isa/isareg.h>
82#include <isa/fdreg.h>
83#include <isa/fdc.h>
84#include <isa/rtc.h>
85
86/* misuse a flag to identify format operation */
87#define B_FORMAT B_XXX
88
89/* configuration flags */
90#define FDC_PRETEND_D0 (1 << 0) /* pretend drive 0 to be there */
91#define FDC_NO_FIFO (1 << 2) /* do not enable FIFO */
92
93/* internally used only, not really from CMOS: */
94#define RTCFDT_144M_PRETENDED 0x1000
95
96/* error returns for fd_cmd() */
97#define FD_FAILED -1
98#define FD_NOT_VALID -2
99#define FDC_ERRMAX 100 /* do not log more */
100
101#define NUMTYPES 17
102#define NUMDENS (NUMTYPES - 7)
103
104/* These defines (-1) must match index for fd_types */
105#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */
106#define NO_TYPE 0 /* must match NO_TYPE in ft.c */
107#define FD_1720 1
108#define FD_1480 2
109#define FD_1440 3
110#define FD_1200 4
111#define FD_820 5
112#define FD_800 6
113#define FD_720 7
114#define FD_360 8
115#define FD_640 9
116#define FD_1232 10
117
118#define FD_1480in5_25 11
119#define FD_1440in5_25 12
120#define FD_820in5_25 13
121#define FD_800in5_25 14
122#define FD_720in5_25 15
123#define FD_360in5_25 16
124#define FD_640in5_25 17
125
126
127static struct fd_type fd_types[NUMTYPES] =
128{
129{ 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */
130{ 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */
131{ 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */
132{ 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */
133{ 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /* 820K in HD 3.5in */
134{ 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /* 800K in HD 3.5in */
135{ 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /* 720K in HD 3.5in */
136{ 9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /* 360K in DD 5.25in */
137{ 8,2,0xFF,0x2A,80,1280,1,FDC_250KBPS,2,0x50,1 }, /* 640K in DD 5.25in */
138{ 8,3,0xFF,0x35,77,1232,1,FDC_500KBPS,2,0x74,1 }, /* 1.23M in HD 5.25in */
139
140{ 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */
141{ 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */
142{ 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /* 820K in HD 5.25in */
143{ 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /* 800K in HD 5.25in */
144{ 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /* 720K in HD 5.25in */
145{ 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /* 360K in HD 5.25in */
146{ 8,2,0xFF,0x2A,80,1280,1,FDC_300KBPS,2,0x50,1 }, /* 640K in HD 5.25in */
147};
148
149#define DRVS_PER_CTLR 2 /* 2 floppies */
150
151/***********************************************************************\
152* Per controller structure. *
153\***********************************************************************/
154static devclass_t fdc_devclass;
155
156/***********************************************************************\
157* Per drive structure. *
158* N per controller (DRVS_PER_CTLR) *
159\***********************************************************************/
160struct fd_data {
161 struct fdc_data *fdc; /* pointer to controller structure */
162 int fdsu; /* this units number on this controller */
163 int type; /* Drive type (FD_1440...) */
164 struct fd_type *ft; /* pointer to the type descriptor */
165 int flags;
166#define FD_OPEN 0x01 /* it's open */
167#define FD_ACTIVE 0x02 /* it's active */
168#define FD_MOTOR 0x04 /* motor should be on */
169#define FD_MOTOR_WAIT 0x08 /* motor coming up */
170 int skip;
171 int hddrv;
172#define FD_NO_TRACK -2
173 int track; /* where we think the head is */
174 int options; /* user configurable options, see ioctl_fd.h */
175 struct callout_handle toffhandle;
176 struct callout_handle tohandle;
177 struct devstat device_stats;
178 device_t dev;
179 fdu_t fdu;
180};
181
182struct fdc_ivars {
183 int fdunit;
184};
185static devclass_t fd_devclass;
186
187/***********************************************************************\
188* Throughout this file the following conventions will be used: *
189* fd is a pointer to the fd_data struct for the drive in question *
190* fdc is a pointer to the fdc_data struct for the controller *
191* fdu is the floppy drive unit number *
192* fdcu is the floppy controller unit number *
193* fdsu is the floppy drive unit number on that controller. (sub-unit) *
194\***********************************************************************/
195
196/* needed for ft driver, thus exported */
197int in_fdc(struct fdc_data *);
198int out_fdc(struct fdc_data *, int);
199
200/* internal functions */
201static void fdc_intr(void *);
202static void set_motor(struct fdc_data *, int, int);
203# define TURNON 1
204# define TURNOFF 0
205static timeout_t fd_turnoff;
206static timeout_t fd_motor_on;
207static void fd_turnon(struct fd_data *);
208static void fdc_reset(fdc_p);
209static int fd_in(struct fdc_data *, int *);
210static void fdstart(struct fdc_data *);
211static timeout_t fd_iotimeout;
212static timeout_t fd_pseudointr;
213static int fdstate(struct fdc_data *);
214static int retrier(struct fdc_data *);
215static int fdformat(dev_t, struct fd_formb *, struct proc *);
216
217static int enable_fifo(fdc_p fdc);
218
219static int fifo_threshold = 8; /* XXX: should be accessible via sysctl */
220
221
222#define DEVIDLE 0
223#define FINDWORK 1
224#define DOSEEK 2
225#define SEEKCOMPLETE 3
226#define IOCOMPLETE 4
227#define RECALCOMPLETE 5
228#define STARTRECAL 6
229#define RESETCTLR 7
230#define SEEKWAIT 8
231#define RECALWAIT 9
232#define MOTORWAIT 10
233#define IOTIMEDOUT 11
234#define RESETCOMPLETE 12
235#define PIOREAD 13
236
237#ifdef FDC_DEBUG
238static char const * const fdstates[] =
239{
240"DEVIDLE",
241"FINDWORK",
242"DOSEEK",
243"SEEKCOMPLETE",
244"IOCOMPLETE",
245"RECALCOMPLETE",
246"STARTRECAL",
247"RESETCTLR",
248"SEEKWAIT",
249"RECALWAIT",
250"MOTORWAIT",
251"IOTIMEDOUT",
252"RESETCOMPLETE",
253"PIOREAD",
254};
255
256/* CAUTION: fd_debug causes huge amounts of logging output */
257static int volatile fd_debug = 0;
258#define TRACE0(arg) if(fd_debug) printf(arg)
259#define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2)
260#else /* FDC_DEBUG */
261#define TRACE0(arg)
262#define TRACE1(arg1, arg2)
263#endif /* FDC_DEBUG */
264
265static void
266fdout_wr(fdc_p fdc, u_int8_t v)
267{
268 bus_space_write_1(fdc->portt, fdc->porth, FDOUT+fdc->port_off, v);
269}
270
271static u_int8_t
272fdsts_rd(fdc_p fdc)
273{
274 return bus_space_read_1(fdc->portt, fdc->porth, FDSTS+fdc->port_off);
275}
276
277static void
278fddata_wr(fdc_p fdc, u_int8_t v)
279{
280 bus_space_write_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off, v);
281}
282
283static u_int8_t
284fddata_rd(fdc_p fdc)
285{
286 return bus_space_read_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off);
287}
288
289static void
290fdctl_wr_isa(fdc_p fdc, u_int8_t v)
291{
292 bus_space_write_1(fdc->ctlt, fdc->ctlh, 0, v);
293}
294
295static void
296fdctl_wr_pcmcia(fdc_p fdc, u_int8_t v)
297{
298 bus_space_write_1(fdc->portt, fdc->porth, FDCTL+fdc->port_off, v);
299}
300
301#if 0
302
303static u_int8_t
304fdin_rd(fdc_p fdc)
305{
306 return bus_space_read_1(fdc->portt, fdc->porth, FDIN);
307}
308
309#endif
310
311static d_open_t Fdopen; /* NOTE, not fdopen */
312static d_close_t fdclose;
313static d_ioctl_t fdioctl;
314static d_strategy_t fdstrategy;
315
316#define CDEV_MAJOR 9
317#define BDEV_MAJOR 2
318
319static struct cdevsw fd_cdevsw = {
320 /* open */ Fdopen,
321 /* close */ fdclose,
322 /* read */ physread,
323 /* write */ physwrite,
324 /* ioctl */ fdioctl,
325 /* poll */ nopoll,
326 /* mmap */ nommap,
327 /* strategy */ fdstrategy,
328 /* name */ "fd",
329 /* maj */ CDEV_MAJOR,
330 /* dump */ nodump,
331 /* psize */ nopsize,
332 /* flags */ D_DISK,
333 /* bmaj */ BDEV_MAJOR
334};
335
336static int
337fdc_err(struct fdc_data *fdc, const char *s)
338{
339 fdc->fdc_errs++;
340 if (s) {
341 if (fdc->fdc_errs < FDC_ERRMAX)
342 device_printf(fdc->fdc_dev, "%s", s);
343 else if (fdc->fdc_errs == FDC_ERRMAX)
344 device_printf(fdc->fdc_dev, "too many errors, not "
345 "logging any more\n");
346 }
347
348 return FD_FAILED;
349}
350
351/*
352 * fd_cmd: Send a command to the chip. Takes a varargs with this structure:
353 * Unit number,
354 * # of output bytes, output bytes as ints ...,
355 * # of input bytes, input bytes as ints ...
356 */
357static int
358fd_cmd(struct fdc_data *fdc, int n_out, ...)
359{
360 u_char cmd;
361 int n_in;
362 int n;
363 va_list ap;
364
365 va_start(ap, n_out);
366 cmd = (u_char)(va_arg(ap, int));
367 va_end(ap);
368 va_start(ap, n_out);
369 for (n = 0; n < n_out; n++)
370 {
371 if (out_fdc(fdc, va_arg(ap, int)) < 0)
372 {
373 char msg[50];
374 snprintf(msg, sizeof(msg),
375 "cmd %x failed at out byte %d of %d\n",
376 cmd, n + 1, n_out);
377 return fdc_err(fdc, msg);
378 }
379 }
380 n_in = va_arg(ap, int);
381 for (n = 0; n < n_in; n++)
382 {
383 int *ptr = va_arg(ap, int *);
384 if (fd_in(fdc, ptr) < 0)
385 {
386 char msg[50];
387 snprintf(msg, sizeof(msg),
388 "cmd %02x failed at in byte %d of %d\n",
389 cmd, n + 1, n_in);
390 return fdc_err(fdc, msg);
391 }
392 }
393
394 return 0;
395}
396
397static int
398enable_fifo(fdc_p fdc)
399{
400 int i, j;
401
402 if ((fdc->flags & FDC_HAS_FIFO) == 0) {
403
404 /*
405 * XXX:
406 * Cannot use fd_cmd the normal way here, since
407 * this might be an invalid command. Thus we send the
408 * first byte, and check for an early turn of data directon.
409 */
410
411 if (out_fdc(fdc, I8207X_CONFIGURE) < 0)
412 return fdc_err(fdc, "Enable FIFO failed\n");
413
414 /* If command is invalid, return */
415 j = 100000;
416 while ((i = fdsts_rd(fdc) & (NE7_DIO | NE7_RQM))
417 != NE7_RQM && j-- > 0)
418 if (i == (NE7_DIO | NE7_RQM)) {
419 fdc_reset(fdc);
420 return FD_FAILED;
421 }
422 if (j<0 ||
423 fd_cmd(fdc, 3,
424 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) {
425 fdc_reset(fdc);
426 return fdc_err(fdc, "Enable FIFO failed\n");
427 }
428 fdc->flags |= FDC_HAS_FIFO;
429 return 0;
430 }
431 if (fd_cmd(fdc, 4,
432 I8207X_CONFIGURE, 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0)
433 return fdc_err(fdc, "Re-enable FIFO failed\n");
434 return 0;
435}
436
437static int
438fd_sense_drive_status(fdc_p fdc, int *st3p)
439{
440 int st3;
441
442 if (fd_cmd(fdc, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3))
443 {
444 return fdc_err(fdc, "Sense Drive Status failed\n");
445 }
446 if (st3p)
447 *st3p = st3;
448
449 return 0;
450}
451
452static int
453fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
454{
455 int cyl, st0, ret;
456
457 ret = fd_cmd(fdc, 1, NE7CMD_SENSEI, 1, &st0);
458 if (ret) {
459 (void)fdc_err(fdc,
460 "sense intr err reading stat reg 0\n");
461 return ret;
462 }
463
464 if (st0p)
465 *st0p = st0;
466
467 if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV) {
468 /*
469 * There doesn't seem to have been an interrupt.
470 */
471 return FD_NOT_VALID;
472 }
473
474 if (fd_in(fdc, &cyl) < 0) {
475 return fdc_err(fdc, "can't get cyl num\n");
476 }
477
478 if (cylp)
479 *cylp = cyl;
480
481 return 0;
482}
483
484
485static int
486fd_read_status(fdc_p fdc, int fdsu)
487{
488 int i, ret;
489
490 for (i = 0; i < 7; i++) {
491 /*
492 * XXX types are poorly chosen. Only bytes can by read
493 * from the hardware, but fdc->status[] wants u_ints and
494 * fd_in() gives ints.
495 */
496 int status;
497
498 ret = fd_in(fdc, &status);
499 fdc->status[i] = status;
500 if (ret != 0)
501 break;
502 }
503
504 if (ret == 0)
505 fdc->flags |= FDC_STAT_VALID;
506 else
507 fdc->flags &= ~FDC_STAT_VALID;
508
509 return ret;
510}
511
512/****************************************************************************/
513/* autoconfiguration stuff */
514/****************************************************************************/
515
516static int
517fdc_alloc_resources(struct fdc_data *fdc)
518{
519 device_t dev;
520 int ispnp, ispcmcia;
521
522 dev = fdc->fdc_dev;
523 ispnp = (fdc->flags & FDC_ISPNP) != 0;
524 ispcmcia = (fdc->flags & FDC_ISPCMCIA) != 0;
525 fdc->rid_ioport = fdc->rid_irq = fdc->rid_drq = 0;
526 fdc->res_ioport = fdc->res_irq = fdc->res_drq = 0;
527
528 /*
529 * On standard ISA, we don't just use an 8 port range
530 * (e.g. 0x3f0-0x3f7) since that covers an IDE control
531 * register at 0x3f6.
532 *
533 * Isn't PC hardware wonderful.
534 *
535 * The Y-E Data PCMCIA FDC doesn't have this problem, it
536 * uses the register with offset 6 for pseudo-DMA, and the
537 * one with offset 7 as control register.
538 */
539 fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
540 &fdc->rid_ioport, 0ul, ~0ul,
541 ispcmcia ? 8 : (ispnp ? 1 : 6),
542 RF_ACTIVE);
543 if (fdc->res_ioport == 0) {
544 device_printf(dev, "cannot reserve I/O port range\n");
545 return ENXIO;
546 }
547 fdc->portt = rman_get_bustag(fdc->res_ioport);
548 fdc->porth = rman_get_bushandle(fdc->res_ioport);
549
550 if (!ispcmcia) {
551 /*
552 * Some BIOSen report the device at 0x3f2-0x3f5,0x3f7
553 * and some at 0x3f0-0x3f5,0x3f7. We detect the former
554 * by checking the size and adjust the port address
555 * accordingly.
556 */
557 if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 4)
558 fdc->port_off = -2;
559
560 /*
561 * Register the control port range as rid 1 if it
562 * isn't there already. Most PnP BIOSen will have
563 * already done this but non-PnP configurations don't.
564 *
565 * And some (!!) report 0x3f2-0x3f5 and completely
566 * leave out the control register! It seems that some
567 * non-antique controller chips have a different
568 * method of programming the transfer speed which
569 * doesn't require the control register, but it's
570 * mighty bogus as the chip still responds to the
571 * address for the control register.
572 */
573 if (bus_get_resource_count(dev, SYS_RES_IOPORT, 1) == 0) {
574 u_long ctlstart;
575
576 /* Find the control port, usually 0x3f7 */
577 ctlstart = rman_get_start(fdc->res_ioport) +
578 fdc->port_off + 7;
579
580 bus_set_resource(dev, SYS_RES_IOPORT, 1, ctlstart, 1);
581 }
582
583 /*
584 * Now (finally!) allocate the control port.
585 */
586 fdc->rid_ctl = 1;
587 fdc->res_ctl = bus_alloc_resource(dev, SYS_RES_IOPORT,
588 &fdc->rid_ctl,
589 0ul, ~0ul, 1, RF_ACTIVE);
590 if (fdc->res_ctl == 0) {
591 device_printf(dev,
592 "cannot reserve control I/O port range\n");
593 return ENXIO;
594 }
595 fdc->ctlt = rman_get_bustag(fdc->res_ctl);
596 fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
597 }
598
599 fdc->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ,
600 &fdc->rid_irq, 0ul, ~0ul, 1,
601 RF_ACTIVE);
602 if (fdc->res_irq == 0) {
603 device_printf(dev, "cannot reserve interrupt line\n");
604 return ENXIO;
605 }
606
607 if ((fdc->flags & FDC_NODMA) == 0) {
608 fdc->res_drq = bus_alloc_resource(dev, SYS_RES_DRQ,
609 &fdc->rid_drq, 0ul, ~0ul, 1,
610 RF_ACTIVE);
611 if (fdc->res_drq == 0) {
612 device_printf(dev, "cannot reserve DMA request line\n");
613 return ENXIO;
614 }
615 fdc->dmachan = fdc->res_drq->r_start;
616 }
617
618 return 0;
619}
620
621static void
622fdc_release_resources(struct fdc_data *fdc)
623{
624 device_t dev;
625
626 dev = fdc->fdc_dev;
627 if (fdc->res_irq != 0) {
628 bus_deactivate_resource(dev, SYS_RES_IRQ, fdc->rid_irq,
629 fdc->res_irq);
630 bus_release_resource(dev, SYS_RES_IRQ, fdc->rid_irq,
631 fdc->res_irq);
632 }
633 if (fdc->res_ctl != 0) {
634 bus_deactivate_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl,
635 fdc->res_ctl);
636 bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl,
637 fdc->res_ctl);
638 }
639 if (fdc->res_ioport != 0) {
640 bus_deactivate_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport,
641 fdc->res_ioport);
642 bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport,
643 fdc->res_ioport);
644 }
645 if (fdc->res_drq != 0) {
646 bus_deactivate_resource(dev, SYS_RES_DRQ, fdc->rid_drq,
647 fdc->res_drq);
648 bus_release_resource(dev, SYS_RES_DRQ, fdc->rid_drq,
649 fdc->res_drq);
650 }
651}
652
653/****************************************************************************/
654/* autoconfiguration stuff */
655/****************************************************************************/
656
657static struct isa_pnp_id fdc_ids[] = {
658 {0x0007d041, "PC standard floppy disk controller"}, /* PNP0700 */
659 {0x0107d041, "Standard floppy controller supporting MS Device Bay Spec"}, /* PNP0701 */
660 {0}
661};
662
663static int
664fdc_read_ivar(device_t dev, device_t child, int which, u_long *result)
665{
666 struct fdc_ivars *ivars = device_get_ivars(child);
667
668 switch (which) {
669 case FDC_IVAR_FDUNIT:
670 *result = ivars->fdunit;
671 break;
672 default:
673 return ENOENT;
674 }
675 return 0;
676}
677
678/*
679 * fdc controller section.
680 */
681static int
682fdc_probe(device_t dev)
683{
684 int error, ic_type;
685 struct fdc_data *fdc;
686
687 fdc = device_get_softc(dev);
688 bzero(fdc, sizeof *fdc);
689 fdc->fdc_dev = dev;
690 fdc->fdctl_wr = fdctl_wr_isa;
691
692 /* Check pnp ids */
693 error = ISA_PNP_PROBE(device_get_parent(dev), dev, fdc_ids);
694 if (error == ENXIO)
695 return ENXIO;
696 if (error == 0)
697 fdc->flags |= FDC_ISPNP;
698
699 /* Attempt to allocate our resources for the duration of the probe */
700 error = fdc_alloc_resources(fdc);
701 if (error)
702 goto out;
703
704 /* First - lets reset the floppy controller */
705 fdout_wr(fdc, 0);
706 DELAY(100);
707 fdout_wr(fdc, FDO_FRST);
708
709 /* see if it can handle a command */
710 if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240),
711 NE7_SPEC_2(2, 0), 0)) {
712 error = ENXIO;
713 goto out;
714 }
715
716 if (fd_cmd(fdc, 1, NE7CMD_VERSION, 1, &ic_type) == 0) {
717 ic_type = (u_char)ic_type;
718 switch (ic_type) {
719 case 0x80:
720 device_set_desc(dev, "NEC 765 or clone");
721 fdc->fdct = FDC_NE765;
722 break;
723 case 0x81:
724 device_set_desc(dev, "Intel 82077 or clone");
725 fdc->fdct = FDC_I82077;
726 break;
727 case 0x90:
728 device_set_desc(dev, "NEC 72065B or clone");
729 fdc->fdct = FDC_NE72065;
730 break;
731 default:
732 device_set_desc(dev, "generic floppy controller");
733 fdc->fdct = FDC_UNKNOWN;
734 break;
735 }
736 }
737
738out:
739 fdc_release_resources(fdc);
740 return (error);
741}
742
743#if NCARD > 0
744
745static int
746fdc_pccard_probe(device_t dev)
747{
748 int error;
749 struct fdc_data *fdc;
750
751 fdc = device_get_softc(dev);
752 bzero(fdc, sizeof *fdc);
753 fdc->fdc_dev = dev;
754 fdc->fdctl_wr = fdctl_wr_pcmcia;
755
756 fdc->flags |= FDC_ISPCMCIA | FDC_NODMA;
757
758 /* Attempt to allocate our resources for the duration of the probe */
759 error = fdc_alloc_resources(fdc);
760 if (error)
761 goto out;
762
763 /* First - lets reset the floppy controller */
764 fdout_wr(fdc, 0);
765 DELAY(100);
766 fdout_wr(fdc, FDO_FRST);
767
768 /* see if it can handle a command */
769 if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240),
770 NE7_SPEC_2(2, 0), 0)) {
771 error = ENXIO;
772 goto out;
773 }
774
775 device_set_desc(dev, "Y-E Data PCMCIA floppy");
776 fdc->fdct = FDC_NE765;
777
778out:
779 fdc_release_resources(fdc);
780 return (error);
781}
782
783static int
784fdc_pccard_detach(device_t dev)
785{
786 struct fdc_data *fdc;
787 int error;
788
789 fdc = device_get_softc(dev);
790
791 /* have our children detached first */
792 if ((error = bus_generic_detach(dev)))
793 return (error);
794
795 if ((fdc->flags & FDC_ATTACHED) == 0) {
796 device_printf(dev, "already unloaded\n");
797 return (0);
798 }
799 fdc->flags &= ~FDC_ATTACHED;
800
801 BUS_TEARDOWN_INTR(device_get_parent(dev), dev, fdc->res_irq,
802 fdc->fdc_intr);
803 fdc_release_resources(fdc);
804 device_printf(dev, "unload\n");
805 return (0);
806}
807
808#endif /* NCARD > 0 */
809
810/*
811 * Add a child device to the fdc controller. It will then be probed etc.
812 */
813static void
814fdc_add_child(device_t dev, const char *name, int unit)
815{
816 int disabled;
817 struct fdc_ivars *ivar;
818 device_t child;
819
820 ivar = malloc(sizeof *ivar, M_DEVBUF /* XXX */, M_NOWAIT);
821 if (ivar == NULL)
822 return;
823 bzero(ivar, sizeof *ivar);
824 if (resource_int_value(name, unit, "drive", &ivar->fdunit) != 0)
825 ivar->fdunit = 0;
826 child = device_add_child(dev, name, unit);
827 if (child == NULL)
828 return;
829 device_set_ivars(child, ivar);
830 if (resource_int_value(name, unit, "disabled", &disabled) == 0
831 && disabled != 0)
832 device_disable(child);
833}
834
835static int
836fdc_attach(device_t dev)
837{
838 struct fdc_data *fdc;
839 int i, error;
840
841 fdc = device_get_softc(dev);
842 error = fdc_alloc_resources(fdc);
843 if (error) {
844 device_printf(dev, "cannot re-aquire resources\n");
845 return error;
846 }
847 error = BUS_SETUP_INTR(device_get_parent(dev), dev, fdc->res_irq,
848 INTR_TYPE_BIO, fdc_intr, fdc, &fdc->fdc_intr);
849 if (error) {
850 device_printf(dev, "cannot setup interrupt\n");
851 return error;
852 }
853 fdc->fdcu = device_get_unit(dev);
854 fdc->flags |= FDC_ATTACHED;
855
856 if ((fdc->flags & FDC_NODMA) == 0) {
857 /* Acquire the DMA channel forever, The driver will do the rest */
858 /* XXX should integrate with rman */
859 isa_dma_acquire(fdc->dmachan);
860 isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */);
861 }
862 fdc->state = DEVIDLE;
863
864 /* reset controller, turn motor off, clear fdout mirror reg */
865 fdout_wr(fdc, ((fdc->fdout = 0)));
87
88/* configuration flags */
89#define FDC_PRETEND_D0 (1 << 0) /* pretend drive 0 to be there */
90#define FDC_NO_FIFO (1 << 2) /* do not enable FIFO */
91
92/* internally used only, not really from CMOS: */
93#define RTCFDT_144M_PRETENDED 0x1000
94
95/* error returns for fd_cmd() */
96#define FD_FAILED -1
97#define FD_NOT_VALID -2
98#define FDC_ERRMAX 100 /* do not log more */
99
100#define NUMTYPES 17
101#define NUMDENS (NUMTYPES - 7)
102
103/* These defines (-1) must match index for fd_types */
104#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */
105#define NO_TYPE 0 /* must match NO_TYPE in ft.c */
106#define FD_1720 1
107#define FD_1480 2
108#define FD_1440 3
109#define FD_1200 4
110#define FD_820 5
111#define FD_800 6
112#define FD_720 7
113#define FD_360 8
114#define FD_640 9
115#define FD_1232 10
116
117#define FD_1480in5_25 11
118#define FD_1440in5_25 12
119#define FD_820in5_25 13
120#define FD_800in5_25 14
121#define FD_720in5_25 15
122#define FD_360in5_25 16
123#define FD_640in5_25 17
124
125
126static struct fd_type fd_types[NUMTYPES] =
127{
128{ 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */
129{ 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */
130{ 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */
131{ 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */
132{ 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /* 820K in HD 3.5in */
133{ 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /* 800K in HD 3.5in */
134{ 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /* 720K in HD 3.5in */
135{ 9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /* 360K in DD 5.25in */
136{ 8,2,0xFF,0x2A,80,1280,1,FDC_250KBPS,2,0x50,1 }, /* 640K in DD 5.25in */
137{ 8,3,0xFF,0x35,77,1232,1,FDC_500KBPS,2,0x74,1 }, /* 1.23M in HD 5.25in */
138
139{ 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */
140{ 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */
141{ 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /* 820K in HD 5.25in */
142{ 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /* 800K in HD 5.25in */
143{ 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /* 720K in HD 5.25in */
144{ 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /* 360K in HD 5.25in */
145{ 8,2,0xFF,0x2A,80,1280,1,FDC_300KBPS,2,0x50,1 }, /* 640K in HD 5.25in */
146};
147
148#define DRVS_PER_CTLR 2 /* 2 floppies */
149
150/***********************************************************************\
151* Per controller structure. *
152\***********************************************************************/
153static devclass_t fdc_devclass;
154
155/***********************************************************************\
156* Per drive structure. *
157* N per controller (DRVS_PER_CTLR) *
158\***********************************************************************/
159struct fd_data {
160 struct fdc_data *fdc; /* pointer to controller structure */
161 int fdsu; /* this units number on this controller */
162 int type; /* Drive type (FD_1440...) */
163 struct fd_type *ft; /* pointer to the type descriptor */
164 int flags;
165#define FD_OPEN 0x01 /* it's open */
166#define FD_ACTIVE 0x02 /* it's active */
167#define FD_MOTOR 0x04 /* motor should be on */
168#define FD_MOTOR_WAIT 0x08 /* motor coming up */
169 int skip;
170 int hddrv;
171#define FD_NO_TRACK -2
172 int track; /* where we think the head is */
173 int options; /* user configurable options, see ioctl_fd.h */
174 struct callout_handle toffhandle;
175 struct callout_handle tohandle;
176 struct devstat device_stats;
177 device_t dev;
178 fdu_t fdu;
179};
180
181struct fdc_ivars {
182 int fdunit;
183};
184static devclass_t fd_devclass;
185
186/***********************************************************************\
187* Throughout this file the following conventions will be used: *
188* fd is a pointer to the fd_data struct for the drive in question *
189* fdc is a pointer to the fdc_data struct for the controller *
190* fdu is the floppy drive unit number *
191* fdcu is the floppy controller unit number *
192* fdsu is the floppy drive unit number on that controller. (sub-unit) *
193\***********************************************************************/
194
195/* needed for ft driver, thus exported */
196int in_fdc(struct fdc_data *);
197int out_fdc(struct fdc_data *, int);
198
199/* internal functions */
200static void fdc_intr(void *);
201static void set_motor(struct fdc_data *, int, int);
202# define TURNON 1
203# define TURNOFF 0
204static timeout_t fd_turnoff;
205static timeout_t fd_motor_on;
206static void fd_turnon(struct fd_data *);
207static void fdc_reset(fdc_p);
208static int fd_in(struct fdc_data *, int *);
209static void fdstart(struct fdc_data *);
210static timeout_t fd_iotimeout;
211static timeout_t fd_pseudointr;
212static int fdstate(struct fdc_data *);
213static int retrier(struct fdc_data *);
214static int fdformat(dev_t, struct fd_formb *, struct proc *);
215
216static int enable_fifo(fdc_p fdc);
217
218static int fifo_threshold = 8; /* XXX: should be accessible via sysctl */
219
220
221#define DEVIDLE 0
222#define FINDWORK 1
223#define DOSEEK 2
224#define SEEKCOMPLETE 3
225#define IOCOMPLETE 4
226#define RECALCOMPLETE 5
227#define STARTRECAL 6
228#define RESETCTLR 7
229#define SEEKWAIT 8
230#define RECALWAIT 9
231#define MOTORWAIT 10
232#define IOTIMEDOUT 11
233#define RESETCOMPLETE 12
234#define PIOREAD 13
235
236#ifdef FDC_DEBUG
237static char const * const fdstates[] =
238{
239"DEVIDLE",
240"FINDWORK",
241"DOSEEK",
242"SEEKCOMPLETE",
243"IOCOMPLETE",
244"RECALCOMPLETE",
245"STARTRECAL",
246"RESETCTLR",
247"SEEKWAIT",
248"RECALWAIT",
249"MOTORWAIT",
250"IOTIMEDOUT",
251"RESETCOMPLETE",
252"PIOREAD",
253};
254
255/* CAUTION: fd_debug causes huge amounts of logging output */
256static int volatile fd_debug = 0;
257#define TRACE0(arg) if(fd_debug) printf(arg)
258#define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2)
259#else /* FDC_DEBUG */
260#define TRACE0(arg)
261#define TRACE1(arg1, arg2)
262#endif /* FDC_DEBUG */
263
264static void
265fdout_wr(fdc_p fdc, u_int8_t v)
266{
267 bus_space_write_1(fdc->portt, fdc->porth, FDOUT+fdc->port_off, v);
268}
269
270static u_int8_t
271fdsts_rd(fdc_p fdc)
272{
273 return bus_space_read_1(fdc->portt, fdc->porth, FDSTS+fdc->port_off);
274}
275
276static void
277fddata_wr(fdc_p fdc, u_int8_t v)
278{
279 bus_space_write_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off, v);
280}
281
282static u_int8_t
283fddata_rd(fdc_p fdc)
284{
285 return bus_space_read_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off);
286}
287
288static void
289fdctl_wr_isa(fdc_p fdc, u_int8_t v)
290{
291 bus_space_write_1(fdc->ctlt, fdc->ctlh, 0, v);
292}
293
294static void
295fdctl_wr_pcmcia(fdc_p fdc, u_int8_t v)
296{
297 bus_space_write_1(fdc->portt, fdc->porth, FDCTL+fdc->port_off, v);
298}
299
300#if 0
301
302static u_int8_t
303fdin_rd(fdc_p fdc)
304{
305 return bus_space_read_1(fdc->portt, fdc->porth, FDIN);
306}
307
308#endif
309
310static d_open_t Fdopen; /* NOTE, not fdopen */
311static d_close_t fdclose;
312static d_ioctl_t fdioctl;
313static d_strategy_t fdstrategy;
314
315#define CDEV_MAJOR 9
316#define BDEV_MAJOR 2
317
318static struct cdevsw fd_cdevsw = {
319 /* open */ Fdopen,
320 /* close */ fdclose,
321 /* read */ physread,
322 /* write */ physwrite,
323 /* ioctl */ fdioctl,
324 /* poll */ nopoll,
325 /* mmap */ nommap,
326 /* strategy */ fdstrategy,
327 /* name */ "fd",
328 /* maj */ CDEV_MAJOR,
329 /* dump */ nodump,
330 /* psize */ nopsize,
331 /* flags */ D_DISK,
332 /* bmaj */ BDEV_MAJOR
333};
334
335static int
336fdc_err(struct fdc_data *fdc, const char *s)
337{
338 fdc->fdc_errs++;
339 if (s) {
340 if (fdc->fdc_errs < FDC_ERRMAX)
341 device_printf(fdc->fdc_dev, "%s", s);
342 else if (fdc->fdc_errs == FDC_ERRMAX)
343 device_printf(fdc->fdc_dev, "too many errors, not "
344 "logging any more\n");
345 }
346
347 return FD_FAILED;
348}
349
350/*
351 * fd_cmd: Send a command to the chip. Takes a varargs with this structure:
352 * Unit number,
353 * # of output bytes, output bytes as ints ...,
354 * # of input bytes, input bytes as ints ...
355 */
356static int
357fd_cmd(struct fdc_data *fdc, int n_out, ...)
358{
359 u_char cmd;
360 int n_in;
361 int n;
362 va_list ap;
363
364 va_start(ap, n_out);
365 cmd = (u_char)(va_arg(ap, int));
366 va_end(ap);
367 va_start(ap, n_out);
368 for (n = 0; n < n_out; n++)
369 {
370 if (out_fdc(fdc, va_arg(ap, int)) < 0)
371 {
372 char msg[50];
373 snprintf(msg, sizeof(msg),
374 "cmd %x failed at out byte %d of %d\n",
375 cmd, n + 1, n_out);
376 return fdc_err(fdc, msg);
377 }
378 }
379 n_in = va_arg(ap, int);
380 for (n = 0; n < n_in; n++)
381 {
382 int *ptr = va_arg(ap, int *);
383 if (fd_in(fdc, ptr) < 0)
384 {
385 char msg[50];
386 snprintf(msg, sizeof(msg),
387 "cmd %02x failed at in byte %d of %d\n",
388 cmd, n + 1, n_in);
389 return fdc_err(fdc, msg);
390 }
391 }
392
393 return 0;
394}
395
396static int
397enable_fifo(fdc_p fdc)
398{
399 int i, j;
400
401 if ((fdc->flags & FDC_HAS_FIFO) == 0) {
402
403 /*
404 * XXX:
405 * Cannot use fd_cmd the normal way here, since
406 * this might be an invalid command. Thus we send the
407 * first byte, and check for an early turn of data directon.
408 */
409
410 if (out_fdc(fdc, I8207X_CONFIGURE) < 0)
411 return fdc_err(fdc, "Enable FIFO failed\n");
412
413 /* If command is invalid, return */
414 j = 100000;
415 while ((i = fdsts_rd(fdc) & (NE7_DIO | NE7_RQM))
416 != NE7_RQM && j-- > 0)
417 if (i == (NE7_DIO | NE7_RQM)) {
418 fdc_reset(fdc);
419 return FD_FAILED;
420 }
421 if (j<0 ||
422 fd_cmd(fdc, 3,
423 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) {
424 fdc_reset(fdc);
425 return fdc_err(fdc, "Enable FIFO failed\n");
426 }
427 fdc->flags |= FDC_HAS_FIFO;
428 return 0;
429 }
430 if (fd_cmd(fdc, 4,
431 I8207X_CONFIGURE, 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0)
432 return fdc_err(fdc, "Re-enable FIFO failed\n");
433 return 0;
434}
435
436static int
437fd_sense_drive_status(fdc_p fdc, int *st3p)
438{
439 int st3;
440
441 if (fd_cmd(fdc, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3))
442 {
443 return fdc_err(fdc, "Sense Drive Status failed\n");
444 }
445 if (st3p)
446 *st3p = st3;
447
448 return 0;
449}
450
451static int
452fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
453{
454 int cyl, st0, ret;
455
456 ret = fd_cmd(fdc, 1, NE7CMD_SENSEI, 1, &st0);
457 if (ret) {
458 (void)fdc_err(fdc,
459 "sense intr err reading stat reg 0\n");
460 return ret;
461 }
462
463 if (st0p)
464 *st0p = st0;
465
466 if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV) {
467 /*
468 * There doesn't seem to have been an interrupt.
469 */
470 return FD_NOT_VALID;
471 }
472
473 if (fd_in(fdc, &cyl) < 0) {
474 return fdc_err(fdc, "can't get cyl num\n");
475 }
476
477 if (cylp)
478 *cylp = cyl;
479
480 return 0;
481}
482
483
484static int
485fd_read_status(fdc_p fdc, int fdsu)
486{
487 int i, ret;
488
489 for (i = 0; i < 7; i++) {
490 /*
491 * XXX types are poorly chosen. Only bytes can by read
492 * from the hardware, but fdc->status[] wants u_ints and
493 * fd_in() gives ints.
494 */
495 int status;
496
497 ret = fd_in(fdc, &status);
498 fdc->status[i] = status;
499 if (ret != 0)
500 break;
501 }
502
503 if (ret == 0)
504 fdc->flags |= FDC_STAT_VALID;
505 else
506 fdc->flags &= ~FDC_STAT_VALID;
507
508 return ret;
509}
510
511/****************************************************************************/
512/* autoconfiguration stuff */
513/****************************************************************************/
514
515static int
516fdc_alloc_resources(struct fdc_data *fdc)
517{
518 device_t dev;
519 int ispnp, ispcmcia;
520
521 dev = fdc->fdc_dev;
522 ispnp = (fdc->flags & FDC_ISPNP) != 0;
523 ispcmcia = (fdc->flags & FDC_ISPCMCIA) != 0;
524 fdc->rid_ioport = fdc->rid_irq = fdc->rid_drq = 0;
525 fdc->res_ioport = fdc->res_irq = fdc->res_drq = 0;
526
527 /*
528 * On standard ISA, we don't just use an 8 port range
529 * (e.g. 0x3f0-0x3f7) since that covers an IDE control
530 * register at 0x3f6.
531 *
532 * Isn't PC hardware wonderful.
533 *
534 * The Y-E Data PCMCIA FDC doesn't have this problem, it
535 * uses the register with offset 6 for pseudo-DMA, and the
536 * one with offset 7 as control register.
537 */
538 fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
539 &fdc->rid_ioport, 0ul, ~0ul,
540 ispcmcia ? 8 : (ispnp ? 1 : 6),
541 RF_ACTIVE);
542 if (fdc->res_ioport == 0) {
543 device_printf(dev, "cannot reserve I/O port range\n");
544 return ENXIO;
545 }
546 fdc->portt = rman_get_bustag(fdc->res_ioport);
547 fdc->porth = rman_get_bushandle(fdc->res_ioport);
548
549 if (!ispcmcia) {
550 /*
551 * Some BIOSen report the device at 0x3f2-0x3f5,0x3f7
552 * and some at 0x3f0-0x3f5,0x3f7. We detect the former
553 * by checking the size and adjust the port address
554 * accordingly.
555 */
556 if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 4)
557 fdc->port_off = -2;
558
559 /*
560 * Register the control port range as rid 1 if it
561 * isn't there already. Most PnP BIOSen will have
562 * already done this but non-PnP configurations don't.
563 *
564 * And some (!!) report 0x3f2-0x3f5 and completely
565 * leave out the control register! It seems that some
566 * non-antique controller chips have a different
567 * method of programming the transfer speed which
568 * doesn't require the control register, but it's
569 * mighty bogus as the chip still responds to the
570 * address for the control register.
571 */
572 if (bus_get_resource_count(dev, SYS_RES_IOPORT, 1) == 0) {
573 u_long ctlstart;
574
575 /* Find the control port, usually 0x3f7 */
576 ctlstart = rman_get_start(fdc->res_ioport) +
577 fdc->port_off + 7;
578
579 bus_set_resource(dev, SYS_RES_IOPORT, 1, ctlstart, 1);
580 }
581
582 /*
583 * Now (finally!) allocate the control port.
584 */
585 fdc->rid_ctl = 1;
586 fdc->res_ctl = bus_alloc_resource(dev, SYS_RES_IOPORT,
587 &fdc->rid_ctl,
588 0ul, ~0ul, 1, RF_ACTIVE);
589 if (fdc->res_ctl == 0) {
590 device_printf(dev,
591 "cannot reserve control I/O port range\n");
592 return ENXIO;
593 }
594 fdc->ctlt = rman_get_bustag(fdc->res_ctl);
595 fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
596 }
597
598 fdc->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ,
599 &fdc->rid_irq, 0ul, ~0ul, 1,
600 RF_ACTIVE);
601 if (fdc->res_irq == 0) {
602 device_printf(dev, "cannot reserve interrupt line\n");
603 return ENXIO;
604 }
605
606 if ((fdc->flags & FDC_NODMA) == 0) {
607 fdc->res_drq = bus_alloc_resource(dev, SYS_RES_DRQ,
608 &fdc->rid_drq, 0ul, ~0ul, 1,
609 RF_ACTIVE);
610 if (fdc->res_drq == 0) {
611 device_printf(dev, "cannot reserve DMA request line\n");
612 return ENXIO;
613 }
614 fdc->dmachan = fdc->res_drq->r_start;
615 }
616
617 return 0;
618}
619
620static void
621fdc_release_resources(struct fdc_data *fdc)
622{
623 device_t dev;
624
625 dev = fdc->fdc_dev;
626 if (fdc->res_irq != 0) {
627 bus_deactivate_resource(dev, SYS_RES_IRQ, fdc->rid_irq,
628 fdc->res_irq);
629 bus_release_resource(dev, SYS_RES_IRQ, fdc->rid_irq,
630 fdc->res_irq);
631 }
632 if (fdc->res_ctl != 0) {
633 bus_deactivate_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl,
634 fdc->res_ctl);
635 bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl,
636 fdc->res_ctl);
637 }
638 if (fdc->res_ioport != 0) {
639 bus_deactivate_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport,
640 fdc->res_ioport);
641 bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport,
642 fdc->res_ioport);
643 }
644 if (fdc->res_drq != 0) {
645 bus_deactivate_resource(dev, SYS_RES_DRQ, fdc->rid_drq,
646 fdc->res_drq);
647 bus_release_resource(dev, SYS_RES_DRQ, fdc->rid_drq,
648 fdc->res_drq);
649 }
650}
651
652/****************************************************************************/
653/* autoconfiguration stuff */
654/****************************************************************************/
655
656static struct isa_pnp_id fdc_ids[] = {
657 {0x0007d041, "PC standard floppy disk controller"}, /* PNP0700 */
658 {0x0107d041, "Standard floppy controller supporting MS Device Bay Spec"}, /* PNP0701 */
659 {0}
660};
661
662static int
663fdc_read_ivar(device_t dev, device_t child, int which, u_long *result)
664{
665 struct fdc_ivars *ivars = device_get_ivars(child);
666
667 switch (which) {
668 case FDC_IVAR_FDUNIT:
669 *result = ivars->fdunit;
670 break;
671 default:
672 return ENOENT;
673 }
674 return 0;
675}
676
677/*
678 * fdc controller section.
679 */
680static int
681fdc_probe(device_t dev)
682{
683 int error, ic_type;
684 struct fdc_data *fdc;
685
686 fdc = device_get_softc(dev);
687 bzero(fdc, sizeof *fdc);
688 fdc->fdc_dev = dev;
689 fdc->fdctl_wr = fdctl_wr_isa;
690
691 /* Check pnp ids */
692 error = ISA_PNP_PROBE(device_get_parent(dev), dev, fdc_ids);
693 if (error == ENXIO)
694 return ENXIO;
695 if (error == 0)
696 fdc->flags |= FDC_ISPNP;
697
698 /* Attempt to allocate our resources for the duration of the probe */
699 error = fdc_alloc_resources(fdc);
700 if (error)
701 goto out;
702
703 /* First - lets reset the floppy controller */
704 fdout_wr(fdc, 0);
705 DELAY(100);
706 fdout_wr(fdc, FDO_FRST);
707
708 /* see if it can handle a command */
709 if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240),
710 NE7_SPEC_2(2, 0), 0)) {
711 error = ENXIO;
712 goto out;
713 }
714
715 if (fd_cmd(fdc, 1, NE7CMD_VERSION, 1, &ic_type) == 0) {
716 ic_type = (u_char)ic_type;
717 switch (ic_type) {
718 case 0x80:
719 device_set_desc(dev, "NEC 765 or clone");
720 fdc->fdct = FDC_NE765;
721 break;
722 case 0x81:
723 device_set_desc(dev, "Intel 82077 or clone");
724 fdc->fdct = FDC_I82077;
725 break;
726 case 0x90:
727 device_set_desc(dev, "NEC 72065B or clone");
728 fdc->fdct = FDC_NE72065;
729 break;
730 default:
731 device_set_desc(dev, "generic floppy controller");
732 fdc->fdct = FDC_UNKNOWN;
733 break;
734 }
735 }
736
737out:
738 fdc_release_resources(fdc);
739 return (error);
740}
741
742#if NCARD > 0
743
744static int
745fdc_pccard_probe(device_t dev)
746{
747 int error;
748 struct fdc_data *fdc;
749
750 fdc = device_get_softc(dev);
751 bzero(fdc, sizeof *fdc);
752 fdc->fdc_dev = dev;
753 fdc->fdctl_wr = fdctl_wr_pcmcia;
754
755 fdc->flags |= FDC_ISPCMCIA | FDC_NODMA;
756
757 /* Attempt to allocate our resources for the duration of the probe */
758 error = fdc_alloc_resources(fdc);
759 if (error)
760 goto out;
761
762 /* First - lets reset the floppy controller */
763 fdout_wr(fdc, 0);
764 DELAY(100);
765 fdout_wr(fdc, FDO_FRST);
766
767 /* see if it can handle a command */
768 if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240),
769 NE7_SPEC_2(2, 0), 0)) {
770 error = ENXIO;
771 goto out;
772 }
773
774 device_set_desc(dev, "Y-E Data PCMCIA floppy");
775 fdc->fdct = FDC_NE765;
776
777out:
778 fdc_release_resources(fdc);
779 return (error);
780}
781
782static int
783fdc_pccard_detach(device_t dev)
784{
785 struct fdc_data *fdc;
786 int error;
787
788 fdc = device_get_softc(dev);
789
790 /* have our children detached first */
791 if ((error = bus_generic_detach(dev)))
792 return (error);
793
794 if ((fdc->flags & FDC_ATTACHED) == 0) {
795 device_printf(dev, "already unloaded\n");
796 return (0);
797 }
798 fdc->flags &= ~FDC_ATTACHED;
799
800 BUS_TEARDOWN_INTR(device_get_parent(dev), dev, fdc->res_irq,
801 fdc->fdc_intr);
802 fdc_release_resources(fdc);
803 device_printf(dev, "unload\n");
804 return (0);
805}
806
807#endif /* NCARD > 0 */
808
809/*
810 * Add a child device to the fdc controller. It will then be probed etc.
811 */
812static void
813fdc_add_child(device_t dev, const char *name, int unit)
814{
815 int disabled;
816 struct fdc_ivars *ivar;
817 device_t child;
818
819 ivar = malloc(sizeof *ivar, M_DEVBUF /* XXX */, M_NOWAIT);
820 if (ivar == NULL)
821 return;
822 bzero(ivar, sizeof *ivar);
823 if (resource_int_value(name, unit, "drive", &ivar->fdunit) != 0)
824 ivar->fdunit = 0;
825 child = device_add_child(dev, name, unit);
826 if (child == NULL)
827 return;
828 device_set_ivars(child, ivar);
829 if (resource_int_value(name, unit, "disabled", &disabled) == 0
830 && disabled != 0)
831 device_disable(child);
832}
833
834static int
835fdc_attach(device_t dev)
836{
837 struct fdc_data *fdc;
838 int i, error;
839
840 fdc = device_get_softc(dev);
841 error = fdc_alloc_resources(fdc);
842 if (error) {
843 device_printf(dev, "cannot re-aquire resources\n");
844 return error;
845 }
846 error = BUS_SETUP_INTR(device_get_parent(dev), dev, fdc->res_irq,
847 INTR_TYPE_BIO, fdc_intr, fdc, &fdc->fdc_intr);
848 if (error) {
849 device_printf(dev, "cannot setup interrupt\n");
850 return error;
851 }
852 fdc->fdcu = device_get_unit(dev);
853 fdc->flags |= FDC_ATTACHED;
854
855 if ((fdc->flags & FDC_NODMA) == 0) {
856 /* Acquire the DMA channel forever, The driver will do the rest */
857 /* XXX should integrate with rman */
858 isa_dma_acquire(fdc->dmachan);
859 isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */);
860 }
861 fdc->state = DEVIDLE;
862
863 /* reset controller, turn motor off, clear fdout mirror reg */
864 fdout_wr(fdc, ((fdc->fdout = 0)));
866 bufq_init(&fdc->head);
865 bioq_init(&fdc->head);
867
868 /*
869 * Probe and attach any children. We should probably detect
870 * devices from the BIOS unless overridden.
871 */
872 for (i = resource_query_string(-1, "at", device_get_nameunit(dev));
873 i != -1;
874 i = resource_query_string(i, "at", device_get_nameunit(dev)))
875 fdc_add_child(dev, resource_query_name(i),
876 resource_query_unit(i));
877
878 return (bus_generic_attach(dev));
879}
880
881static int
882fdc_print_child(device_t me, device_t child)
883{
884 int retval = 0;
885
886 retval += bus_print_child_header(me, child);
887 retval += printf(" on %s drive %d\n", device_get_nameunit(me),
888 fdc_get_fdunit(child));
889
890 return (retval);
891}
892
893static device_method_t fdc_methods[] = {
894 /* Device interface */
895 DEVMETHOD(device_probe, fdc_probe),
896 DEVMETHOD(device_attach, fdc_attach),
897 DEVMETHOD(device_detach, bus_generic_detach),
898 DEVMETHOD(device_shutdown, bus_generic_shutdown),
899 DEVMETHOD(device_suspend, bus_generic_suspend),
900 DEVMETHOD(device_resume, bus_generic_resume),
901
902 /* Bus interface */
903 DEVMETHOD(bus_print_child, fdc_print_child),
904 DEVMETHOD(bus_read_ivar, fdc_read_ivar),
905 /* Our children never use any other bus interface methods. */
906
907 { 0, 0 }
908};
909
910static driver_t fdc_driver = {
911 "fdc",
912 fdc_methods,
913 sizeof(struct fdc_data)
914};
915
916DRIVER_MODULE(fdc, isa, fdc_driver, fdc_devclass, 0, 0);
917
918#if NCARD > 0
919
920static device_method_t fdc_pccard_methods[] = {
921 /* Device interface */
922 DEVMETHOD(device_probe, fdc_pccard_probe),
923 DEVMETHOD(device_attach, fdc_attach),
924 DEVMETHOD(device_detach, fdc_pccard_detach),
925 DEVMETHOD(device_shutdown, bus_generic_shutdown),
926 DEVMETHOD(device_suspend, bus_generic_suspend),
927 DEVMETHOD(device_resume, bus_generic_resume),
928
929 /* Bus interface */
930 DEVMETHOD(bus_print_child, fdc_print_child),
931 DEVMETHOD(bus_read_ivar, fdc_read_ivar),
932 /* Our children never use any other bus interface methods. */
933
934 { 0, 0 }
935};
936
937static driver_t fdc_pccard_driver = {
938 "fdc",
939 fdc_pccard_methods,
940 sizeof(struct fdc_data)
941};
942
943DRIVER_MODULE(fdc, pccard, fdc_pccard_driver, fdc_devclass, 0, 0);
944
945#endif /* NCARD > 0 */
946
947/******************************************************************/
948/*
949 * devices attached to the controller section.
950 */
951static int
952fd_probe(device_t dev)
953{
954 int i;
955 u_int fdt, st0, st3;
956 struct fd_data *fd;
957 struct fdc_data *fdc;
958 fdsu_t fdsu;
959 static int fd_fifo = 0;
960
961 fdsu = *(int *)device_get_ivars(dev); /* xxx cheat a bit... */
962 fd = device_get_softc(dev);
963 fdc = device_get_softc(device_get_parent(dev));
964
965 bzero(fd, sizeof *fd);
966 fd->dev = dev;
967 fd->fdc = fdc;
968 fd->fdsu = fdsu;
969 fd->fdu = device_get_unit(dev);
970
971#ifdef __i386__
972 /* look up what bios thinks we have */
973 switch (fd->fdu) {
974 case 0:
975 if ((fdc->flags & FDC_ISPCMCIA))
976 fdt = RTCFDT_144M;
977 else if (device_get_flags(fdc->fdc_dev) & FDC_PRETEND_D0)
978 fdt = RTCFDT_144M | RTCFDT_144M_PRETENDED;
979 else
980 fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
981 break;
982 case 1:
983 fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0);
984 break;
985 default:
986 fdt = RTCFDT_NONE;
987 break;
988 }
989#else
990 fdt = RTCFDT_144M; /* XXX probably */
991#endif
992
993 /* is there a unit? */
994 if (fdt == RTCFDT_NONE)
995 return (ENXIO);
996
997 /* select it */
998 set_motor(fdc, fdsu, TURNON);
999 DELAY(1000000); /* 1 sec */
1000
1001 /* XXX This doesn't work before the first set_motor() */
1002 if (fd_fifo == 0 && fdc->fdct != FDC_NE765 && fdc->fdct != FDC_UNKNOWN
1003 && (device_get_flags(fdc->fdc_dev) & FDC_NO_FIFO) == 0
1004 && enable_fifo(fdc) == 0) {
1005 device_printf(device_get_parent(dev),
1006 "FIFO enabled, %d bytes threshold\n", fifo_threshold);
1007 }
1008 fd_fifo = 1;
1009
1010 if ((fd_cmd(fdc, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0)
1011 && (st3 & NE7_ST3_T0)) {
1012 /* if at track 0, first seek inwards */
1013 /* seek some steps: */
1014 fd_cmd(fdc, 3, NE7CMD_SEEK, fdsu, 10, 0);
1015 DELAY(300000); /* ...wait a moment... */
1016 fd_sense_int(fdc, 0, 0); /* make ctrlr happy */
1017 }
1018
1019 /* If we're at track 0 first seek inwards. */
1020 if ((fd_sense_drive_status(fdc, &st3) == 0) && (st3 & NE7_ST3_T0)) {
1021 /* Seek some steps... */
1022 if (fd_cmd(fdc, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
1023 /* ...wait a moment... */
1024 DELAY(300000);
1025 /* make ctrlr happy: */
1026 fd_sense_int(fdc, 0, 0);
1027 }
1028 }
1029
1030 for (i = 0; i < 2; i++) {
1031 /*
1032 * we must recalibrate twice, just in case the
1033 * heads have been beyond cylinder 76, since most
1034 * FDCs still barf when attempting to recalibrate
1035 * more than 77 steps
1036 */
1037 /* go back to 0: */
1038 if (fd_cmd(fdc, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
1039 /* a second being enough for full stroke seek*/
1040 DELAY(i == 0 ? 1000000 : 300000);
1041
1042 /* anything responding? */
1043 if (fd_sense_int(fdc, &st0, 0) == 0 &&
1044 (st0 & NE7_ST0_EC) == 0)
1045 break; /* already probed succesfully */
1046 }
1047 }
1048
1049 set_motor(fdc, fdsu, TURNOFF);
1050
1051 if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
1052 return (ENXIO);
1053
1054 fd->track = FD_NO_TRACK;
1055 fd->fdc = fdc;
1056 fd->fdsu = fdsu;
1057 fd->options = 0;
1058 callout_handle_init(&fd->toffhandle);
1059 callout_handle_init(&fd->tohandle);
1060
1061 switch (fdt) {
1062 case RTCFDT_12M:
1063 device_set_desc(dev, "1200-KB 5.25\" drive");
1064 fd->type = FD_1200;
1065 break;
1066 case RTCFDT_144M | RTCFDT_144M_PRETENDED:
1067 device_set_desc(dev, "config-pretended 1440-MB 3.5\" drive");
1068 fdt = RTCFDT_144M;
1069 fd->type = FD_1440;
1070 case RTCFDT_144M:
1071 device_set_desc(dev, "1440-KB 3.5\" drive");
1072 fd->type = FD_1440;
1073 break;
1074 case RTCFDT_288M:
1075 case RTCFDT_288M_1:
1076 device_set_desc(dev, "2880-KB 3.5\" drive (in 1440-KB mode)");
1077 fd->type = FD_1440;
1078 break;
1079 case RTCFDT_360K:
1080 device_set_desc(dev, "360-KB 5.25\" drive");
1081 fd->type = FD_360;
1082 break;
1083 case RTCFDT_720K:
1084 printf("720-KB 3.5\" drive");
1085 fd->type = FD_720;
1086 break;
1087 default:
1088 return (ENXIO);
1089 }
1090 return (0);
1091}
1092
1093static int
1094fd_attach(device_t dev)
1095{
1096 struct fd_data *fd;
1097#if 0
1098 int i;
1099 int mynor;
1100 int typemynor;
1101 int typesize;
1102#endif
1103
1104 fd = device_get_softc(dev);
1105
1106 cdevsw_add(&fd_cdevsw); /* XXX */
1107 make_dev(&fd_cdevsw, (fd->fdu << 6),
1108 UID_ROOT, GID_OPERATOR, 0640, "rfd%d", fd->fdu);
1109
1110#if 0
1111 /* Other make_dev() go here. */
1112#endif
1113
1114 /*
1115 * Export the drive to the devstat interface.
1116 */
1117 devstat_add_entry(&fd->device_stats, device_get_name(dev),
1118 device_get_unit(dev), 512, DEVSTAT_NO_ORDERED_TAGS,
1119 DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER,
1120 DEVSTAT_PRIORITY_FD);
1121 return (0);
1122}
1123
1124static int
1125fd_detach(device_t dev)
1126{
1127 struct fd_data *fd;
1128
1129 fd = device_get_softc(dev);
1130 untimeout(fd_turnoff, fd, fd->toffhandle);
1131
1132 return (0);
1133}
1134
1135static device_method_t fd_methods[] = {
1136 /* Device interface */
1137 DEVMETHOD(device_probe, fd_probe),
1138 DEVMETHOD(device_attach, fd_attach),
1139 DEVMETHOD(device_detach, fd_detach),
1140 DEVMETHOD(device_shutdown, bus_generic_shutdown),
1141 DEVMETHOD(device_suspend, bus_generic_suspend), /* XXX */
1142 DEVMETHOD(device_resume, bus_generic_resume), /* XXX */
1143
1144 { 0, 0 }
1145};
1146
1147static driver_t fd_driver = {
1148 "fd",
1149 fd_methods,
1150 sizeof(struct fd_data)
1151};
1152
1153DRIVER_MODULE(fd, fdc, fd_driver, fd_devclass, 0, 0);
1154
1155/****************************************************************************/
1156/* motor control stuff */
1157/* remember to not deselect the drive we're working on */
1158/****************************************************************************/
1159static void
1160set_motor(struct fdc_data *fdc, int fdsu, int turnon)
1161{
1162 int fdout = fdc->fdout;
1163 int needspecify = 0;
1164
1165 if(turnon) {
1166 fdout &= ~FDO_FDSEL;
1167 fdout |= (FDO_MOEN0 << fdsu) + fdsu;
1168 } else
1169 fdout &= ~(FDO_MOEN0 << fdsu);
1170
1171 if(!turnon
1172 && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0)
1173 /* gonna turn off the last drive, put FDC to bed */
1174 fdout &= ~ (FDO_FRST|FDO_FDMAEN);
1175 else {
1176 /* make sure controller is selected and specified */
1177 if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0)
1178 needspecify = 1;
1179 fdout |= (FDO_FRST|FDO_FDMAEN);
1180 }
1181
1182 fdout_wr(fdc, fdout);
1183 fdc->fdout = fdout;
1184 TRACE1("[0x%x->FDOUT]", fdout);
1185
1186 if (needspecify) {
1187 /*
1188 * XXX
1189 * special case: since we have just woken up the FDC
1190 * from its sleep, we silently assume the command will
1191 * be accepted, and do not test for a timeout
1192 */
1193 (void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
1194 NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
1195 0);
1196 if (fdc->flags & FDC_HAS_FIFO)
1197 (void) enable_fifo(fdc);
1198 }
1199}
1200
1201static void
1202fd_turnoff(void *xfd)
1203{
1204 int s;
1205 fd_p fd = xfd;
1206
1207 TRACE1("[fd%d: turnoff]", fd->fdu);
1208
1209 s = splbio();
1210 /*
1211 * Don't turn off the motor yet if the drive is active.
1212 *
1213 * If we got here, this could only mean we missed an interrupt.
1214 * This can e. g. happen on the Y-E Date PCMCIA floppy controller
1215 * after a controller reset. Just schedule a pseudo-interrupt
1216 * so the state machine gets re-entered.
1217 */
1218 if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fd->fdu) {
1219 fdc_intr(fd->fdc);
1220 splx(s);
1221 return;
1222 }
1223
1224 fd->flags &= ~FD_MOTOR;
1225 set_motor(fd->fdc, fd->fdsu, TURNOFF);
1226 splx(s);
1227}
1228
1229static void
1230fd_motor_on(void *xfd)
1231{
1232 int s;
1233 fd_p fd = xfd;
1234
1235 s = splbio();
1236 fd->flags &= ~FD_MOTOR_WAIT;
1237 if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
1238 {
1239 fdc_intr(fd->fdc);
1240 }
1241 splx(s);
1242}
1243
1244static void
1245fd_turnon(fd_p fd)
1246{
1247 if(!(fd->flags & FD_MOTOR))
1248 {
1249 fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT);
1250 set_motor(fd->fdc, fd->fdsu, TURNON);
1251 timeout(fd_motor_on, fd, hz); /* in 1 sec its ok */
1252 }
1253}
1254
1255static void
1256fdc_reset(fdc_p fdc)
1257{
1258 /* Try a reset, keep motor on */
1259 fdout_wr(fdc, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
1260 TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
1261 DELAY(100);
1262 /* enable FDC, but defer interrupts a moment */
1263 fdout_wr(fdc, fdc->fdout & ~FDO_FDMAEN);
1264 TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN);
1265 DELAY(100);
1266 fdout_wr(fdc, fdc->fdout);
1267 TRACE1("[0x%x->FDOUT]", fdc->fdout);
1268
1269 /* XXX after a reset, silently believe the FDC will accept commands */
1270 (void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
1271 NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
1272 0);
1273 if (fdc->flags & FDC_HAS_FIFO)
1274 (void) enable_fifo(fdc);
1275}
1276
1277/****************************************************************************/
1278/* fdc in/out */
1279/****************************************************************************/
1280int
1281in_fdc(struct fdc_data *fdc)
1282{
1283 int i, j = 100000;
1284 while ((i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM))
1285 != (NE7_DIO|NE7_RQM) && j-- > 0)
1286 if (i == NE7_RQM)
1287 return fdc_err(fdc, "ready for output in input\n");
1288 if (j <= 0)
1289 return fdc_err(fdc, bootverbose? "input ready timeout\n": 0);
1290#ifdef FDC_DEBUG
1291 i = fddata_rd(fdc);
1292 TRACE1("[FDDATA->0x%x]", (unsigned char)i);
1293 return(i);
1294#else /* !FDC_DEBUG */
1295 return fddata_rd(fdc);
1296#endif /* FDC_DEBUG */
1297}
1298
1299/*
1300 * fd_in: Like in_fdc, but allows you to see if it worked.
1301 */
1302static int
1303fd_in(struct fdc_data *fdc, int *ptr)
1304{
1305 int i, j = 100000;
1306 while ((i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM))
1307 != (NE7_DIO|NE7_RQM) && j-- > 0)
1308 if (i == NE7_RQM)
1309 return fdc_err(fdc, "ready for output in input\n");
1310 if (j <= 0)
1311 return fdc_err(fdc, bootverbose? "input ready timeout\n": 0);
1312#ifdef FDC_DEBUG
1313 i = fddata_rd(fdc);
1314 TRACE1("[FDDATA->0x%x]", (unsigned char)i);
1315 *ptr = i;
1316 return 0;
1317#else /* !FDC_DEBUG */
1318 i = fddata_rd(fdc);
1319 if (ptr)
1320 *ptr = i;
1321 return 0;
1322#endif /* FDC_DEBUG */
1323}
1324
1325int
1326out_fdc(struct fdc_data *fdc, int x)
1327{
1328 int i;
1329
1330 /* Check that the direction bit is set */
1331 i = 100000;
1332 while ((fdsts_rd(fdc) & NE7_DIO) && i-- > 0);
1333 if (i <= 0) return fdc_err(fdc, "direction bit not set\n");
1334
1335 /* Check that the floppy controller is ready for a command */
1336 i = 100000;
1337 while ((fdsts_rd(fdc) & NE7_RQM) == 0 && i-- > 0);
1338 if (i <= 0)
1339 return fdc_err(fdc, bootverbose? "output ready timeout\n": 0);
1340
1341 /* Send the command and return */
1342 fddata_wr(fdc, x);
1343 TRACE1("[0x%x->FDDATA]", x);
1344 return (0);
1345}
1346
1347/****************************************************************************/
1348/* fdopen/fdclose */
1349/****************************************************************************/
1350int
1351Fdopen(dev_t dev, int flags, int mode, struct proc *p)
1352{
1353 fdu_t fdu = FDUNIT(minor(dev));
1354 int type = FDTYPE(minor(dev));
1355 fd_p fd;
1356 fdc_p fdc;
1357
1358 /* check bounds */
1359 if ((fd = devclass_get_softc(fd_devclass, fdu)) == 0)
1360 return (ENXIO);
1361 fdc = fd->fdc;
1362 if ((fdc == NULL) || (fd->type == NO_TYPE))
1363 return (ENXIO);
1364 if (type > NUMDENS)
1365 return (ENXIO);
1366 if (type == 0)
1367 type = fd->type;
1368 else {
1369 /*
1370 * For each type of basic drive, make sure we are trying
1371 * to open a type it can do,
1372 */
1373 if (type != fd->type) {
1374 switch (fd->type) {
1375 case FD_360:
1376 return (ENXIO);
1377 case FD_720:
1378 if ( type != FD_820
1379 && type != FD_800
1380 && type != FD_640
1381 )
1382 return (ENXIO);
1383 break;
1384 case FD_1200:
1385 switch (type) {
1386 case FD_1480:
1387 type = FD_1480in5_25;
1388 break;
1389 case FD_1440:
1390 type = FD_1440in5_25;
1391 break;
1392 case FD_1232:
1393 break;
1394 case FD_820:
1395 type = FD_820in5_25;
1396 break;
1397 case FD_800:
1398 type = FD_800in5_25;
1399 break;
1400 case FD_720:
1401 type = FD_720in5_25;
1402 break;
1403 case FD_640:
1404 type = FD_640in5_25;
1405 break;
1406 case FD_360:
1407 type = FD_360in5_25;
1408 break;
1409 default:
1410 return(ENXIO);
1411 }
1412 break;
1413 case FD_1440:
1414 if ( type != FD_1720
1415 && type != FD_1480
1416 && type != FD_1200
1417 && type != FD_820
1418 && type != FD_800
1419 && type != FD_720
1420 && type != FD_640
1421 )
1422 return(ENXIO);
1423 break;
1424 }
1425 }
1426 }
1427 fd->ft = fd_types + type - 1;
1428 fd->flags |= FD_OPEN;
1429
1430 return 0;
1431}
1432
1433int
1434fdclose(dev_t dev, int flags, int mode, struct proc *p)
1435{
1436 fdu_t fdu = FDUNIT(minor(dev));
1437 struct fd_data *fd;
1438
1439 fd = devclass_get_softc(fd_devclass, fdu);
1440 fd->flags &= ~FD_OPEN;
1441 fd->options &= ~FDOPT_NORETRY;
1442
1443 return (0);
1444}
1445
1446/****************************************************************************/
1447/* fdstrategy */
1448/****************************************************************************/
1449void
866
867 /*
868 * Probe and attach any children. We should probably detect
869 * devices from the BIOS unless overridden.
870 */
871 for (i = resource_query_string(-1, "at", device_get_nameunit(dev));
872 i != -1;
873 i = resource_query_string(i, "at", device_get_nameunit(dev)))
874 fdc_add_child(dev, resource_query_name(i),
875 resource_query_unit(i));
876
877 return (bus_generic_attach(dev));
878}
879
880static int
881fdc_print_child(device_t me, device_t child)
882{
883 int retval = 0;
884
885 retval += bus_print_child_header(me, child);
886 retval += printf(" on %s drive %d\n", device_get_nameunit(me),
887 fdc_get_fdunit(child));
888
889 return (retval);
890}
891
892static device_method_t fdc_methods[] = {
893 /* Device interface */
894 DEVMETHOD(device_probe, fdc_probe),
895 DEVMETHOD(device_attach, fdc_attach),
896 DEVMETHOD(device_detach, bus_generic_detach),
897 DEVMETHOD(device_shutdown, bus_generic_shutdown),
898 DEVMETHOD(device_suspend, bus_generic_suspend),
899 DEVMETHOD(device_resume, bus_generic_resume),
900
901 /* Bus interface */
902 DEVMETHOD(bus_print_child, fdc_print_child),
903 DEVMETHOD(bus_read_ivar, fdc_read_ivar),
904 /* Our children never use any other bus interface methods. */
905
906 { 0, 0 }
907};
908
909static driver_t fdc_driver = {
910 "fdc",
911 fdc_methods,
912 sizeof(struct fdc_data)
913};
914
915DRIVER_MODULE(fdc, isa, fdc_driver, fdc_devclass, 0, 0);
916
917#if NCARD > 0
918
919static device_method_t fdc_pccard_methods[] = {
920 /* Device interface */
921 DEVMETHOD(device_probe, fdc_pccard_probe),
922 DEVMETHOD(device_attach, fdc_attach),
923 DEVMETHOD(device_detach, fdc_pccard_detach),
924 DEVMETHOD(device_shutdown, bus_generic_shutdown),
925 DEVMETHOD(device_suspend, bus_generic_suspend),
926 DEVMETHOD(device_resume, bus_generic_resume),
927
928 /* Bus interface */
929 DEVMETHOD(bus_print_child, fdc_print_child),
930 DEVMETHOD(bus_read_ivar, fdc_read_ivar),
931 /* Our children never use any other bus interface methods. */
932
933 { 0, 0 }
934};
935
936static driver_t fdc_pccard_driver = {
937 "fdc",
938 fdc_pccard_methods,
939 sizeof(struct fdc_data)
940};
941
942DRIVER_MODULE(fdc, pccard, fdc_pccard_driver, fdc_devclass, 0, 0);
943
944#endif /* NCARD > 0 */
945
946/******************************************************************/
947/*
948 * devices attached to the controller section.
949 */
950static int
951fd_probe(device_t dev)
952{
953 int i;
954 u_int fdt, st0, st3;
955 struct fd_data *fd;
956 struct fdc_data *fdc;
957 fdsu_t fdsu;
958 static int fd_fifo = 0;
959
960 fdsu = *(int *)device_get_ivars(dev); /* xxx cheat a bit... */
961 fd = device_get_softc(dev);
962 fdc = device_get_softc(device_get_parent(dev));
963
964 bzero(fd, sizeof *fd);
965 fd->dev = dev;
966 fd->fdc = fdc;
967 fd->fdsu = fdsu;
968 fd->fdu = device_get_unit(dev);
969
970#ifdef __i386__
971 /* look up what bios thinks we have */
972 switch (fd->fdu) {
973 case 0:
974 if ((fdc->flags & FDC_ISPCMCIA))
975 fdt = RTCFDT_144M;
976 else if (device_get_flags(fdc->fdc_dev) & FDC_PRETEND_D0)
977 fdt = RTCFDT_144M | RTCFDT_144M_PRETENDED;
978 else
979 fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
980 break;
981 case 1:
982 fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0);
983 break;
984 default:
985 fdt = RTCFDT_NONE;
986 break;
987 }
988#else
989 fdt = RTCFDT_144M; /* XXX probably */
990#endif
991
992 /* is there a unit? */
993 if (fdt == RTCFDT_NONE)
994 return (ENXIO);
995
996 /* select it */
997 set_motor(fdc, fdsu, TURNON);
998 DELAY(1000000); /* 1 sec */
999
1000 /* XXX This doesn't work before the first set_motor() */
1001 if (fd_fifo == 0 && fdc->fdct != FDC_NE765 && fdc->fdct != FDC_UNKNOWN
1002 && (device_get_flags(fdc->fdc_dev) & FDC_NO_FIFO) == 0
1003 && enable_fifo(fdc) == 0) {
1004 device_printf(device_get_parent(dev),
1005 "FIFO enabled, %d bytes threshold\n", fifo_threshold);
1006 }
1007 fd_fifo = 1;
1008
1009 if ((fd_cmd(fdc, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0)
1010 && (st3 & NE7_ST3_T0)) {
1011 /* if at track 0, first seek inwards */
1012 /* seek some steps: */
1013 fd_cmd(fdc, 3, NE7CMD_SEEK, fdsu, 10, 0);
1014 DELAY(300000); /* ...wait a moment... */
1015 fd_sense_int(fdc, 0, 0); /* make ctrlr happy */
1016 }
1017
1018 /* If we're at track 0 first seek inwards. */
1019 if ((fd_sense_drive_status(fdc, &st3) == 0) && (st3 & NE7_ST3_T0)) {
1020 /* Seek some steps... */
1021 if (fd_cmd(fdc, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
1022 /* ...wait a moment... */
1023 DELAY(300000);
1024 /* make ctrlr happy: */
1025 fd_sense_int(fdc, 0, 0);
1026 }
1027 }
1028
1029 for (i = 0; i < 2; i++) {
1030 /*
1031 * we must recalibrate twice, just in case the
1032 * heads have been beyond cylinder 76, since most
1033 * FDCs still barf when attempting to recalibrate
1034 * more than 77 steps
1035 */
1036 /* go back to 0: */
1037 if (fd_cmd(fdc, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
1038 /* a second being enough for full stroke seek*/
1039 DELAY(i == 0 ? 1000000 : 300000);
1040
1041 /* anything responding? */
1042 if (fd_sense_int(fdc, &st0, 0) == 0 &&
1043 (st0 & NE7_ST0_EC) == 0)
1044 break; /* already probed succesfully */
1045 }
1046 }
1047
1048 set_motor(fdc, fdsu, TURNOFF);
1049
1050 if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
1051 return (ENXIO);
1052
1053 fd->track = FD_NO_TRACK;
1054 fd->fdc = fdc;
1055 fd->fdsu = fdsu;
1056 fd->options = 0;
1057 callout_handle_init(&fd->toffhandle);
1058 callout_handle_init(&fd->tohandle);
1059
1060 switch (fdt) {
1061 case RTCFDT_12M:
1062 device_set_desc(dev, "1200-KB 5.25\" drive");
1063 fd->type = FD_1200;
1064 break;
1065 case RTCFDT_144M | RTCFDT_144M_PRETENDED:
1066 device_set_desc(dev, "config-pretended 1440-MB 3.5\" drive");
1067 fdt = RTCFDT_144M;
1068 fd->type = FD_1440;
1069 case RTCFDT_144M:
1070 device_set_desc(dev, "1440-KB 3.5\" drive");
1071 fd->type = FD_1440;
1072 break;
1073 case RTCFDT_288M:
1074 case RTCFDT_288M_1:
1075 device_set_desc(dev, "2880-KB 3.5\" drive (in 1440-KB mode)");
1076 fd->type = FD_1440;
1077 break;
1078 case RTCFDT_360K:
1079 device_set_desc(dev, "360-KB 5.25\" drive");
1080 fd->type = FD_360;
1081 break;
1082 case RTCFDT_720K:
1083 printf("720-KB 3.5\" drive");
1084 fd->type = FD_720;
1085 break;
1086 default:
1087 return (ENXIO);
1088 }
1089 return (0);
1090}
1091
1092static int
1093fd_attach(device_t dev)
1094{
1095 struct fd_data *fd;
1096#if 0
1097 int i;
1098 int mynor;
1099 int typemynor;
1100 int typesize;
1101#endif
1102
1103 fd = device_get_softc(dev);
1104
1105 cdevsw_add(&fd_cdevsw); /* XXX */
1106 make_dev(&fd_cdevsw, (fd->fdu << 6),
1107 UID_ROOT, GID_OPERATOR, 0640, "rfd%d", fd->fdu);
1108
1109#if 0
1110 /* Other make_dev() go here. */
1111#endif
1112
1113 /*
1114 * Export the drive to the devstat interface.
1115 */
1116 devstat_add_entry(&fd->device_stats, device_get_name(dev),
1117 device_get_unit(dev), 512, DEVSTAT_NO_ORDERED_TAGS,
1118 DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER,
1119 DEVSTAT_PRIORITY_FD);
1120 return (0);
1121}
1122
1123static int
1124fd_detach(device_t dev)
1125{
1126 struct fd_data *fd;
1127
1128 fd = device_get_softc(dev);
1129 untimeout(fd_turnoff, fd, fd->toffhandle);
1130
1131 return (0);
1132}
1133
1134static device_method_t fd_methods[] = {
1135 /* Device interface */
1136 DEVMETHOD(device_probe, fd_probe),
1137 DEVMETHOD(device_attach, fd_attach),
1138 DEVMETHOD(device_detach, fd_detach),
1139 DEVMETHOD(device_shutdown, bus_generic_shutdown),
1140 DEVMETHOD(device_suspend, bus_generic_suspend), /* XXX */
1141 DEVMETHOD(device_resume, bus_generic_resume), /* XXX */
1142
1143 { 0, 0 }
1144};
1145
1146static driver_t fd_driver = {
1147 "fd",
1148 fd_methods,
1149 sizeof(struct fd_data)
1150};
1151
1152DRIVER_MODULE(fd, fdc, fd_driver, fd_devclass, 0, 0);
1153
1154/****************************************************************************/
1155/* motor control stuff */
1156/* remember to not deselect the drive we're working on */
1157/****************************************************************************/
1158static void
1159set_motor(struct fdc_data *fdc, int fdsu, int turnon)
1160{
1161 int fdout = fdc->fdout;
1162 int needspecify = 0;
1163
1164 if(turnon) {
1165 fdout &= ~FDO_FDSEL;
1166 fdout |= (FDO_MOEN0 << fdsu) + fdsu;
1167 } else
1168 fdout &= ~(FDO_MOEN0 << fdsu);
1169
1170 if(!turnon
1171 && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0)
1172 /* gonna turn off the last drive, put FDC to bed */
1173 fdout &= ~ (FDO_FRST|FDO_FDMAEN);
1174 else {
1175 /* make sure controller is selected and specified */
1176 if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0)
1177 needspecify = 1;
1178 fdout |= (FDO_FRST|FDO_FDMAEN);
1179 }
1180
1181 fdout_wr(fdc, fdout);
1182 fdc->fdout = fdout;
1183 TRACE1("[0x%x->FDOUT]", fdout);
1184
1185 if (needspecify) {
1186 /*
1187 * XXX
1188 * special case: since we have just woken up the FDC
1189 * from its sleep, we silently assume the command will
1190 * be accepted, and do not test for a timeout
1191 */
1192 (void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
1193 NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
1194 0);
1195 if (fdc->flags & FDC_HAS_FIFO)
1196 (void) enable_fifo(fdc);
1197 }
1198}
1199
1200static void
1201fd_turnoff(void *xfd)
1202{
1203 int s;
1204 fd_p fd = xfd;
1205
1206 TRACE1("[fd%d: turnoff]", fd->fdu);
1207
1208 s = splbio();
1209 /*
1210 * Don't turn off the motor yet if the drive is active.
1211 *
1212 * If we got here, this could only mean we missed an interrupt.
1213 * This can e. g. happen on the Y-E Date PCMCIA floppy controller
1214 * after a controller reset. Just schedule a pseudo-interrupt
1215 * so the state machine gets re-entered.
1216 */
1217 if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fd->fdu) {
1218 fdc_intr(fd->fdc);
1219 splx(s);
1220 return;
1221 }
1222
1223 fd->flags &= ~FD_MOTOR;
1224 set_motor(fd->fdc, fd->fdsu, TURNOFF);
1225 splx(s);
1226}
1227
1228static void
1229fd_motor_on(void *xfd)
1230{
1231 int s;
1232 fd_p fd = xfd;
1233
1234 s = splbio();
1235 fd->flags &= ~FD_MOTOR_WAIT;
1236 if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
1237 {
1238 fdc_intr(fd->fdc);
1239 }
1240 splx(s);
1241}
1242
1243static void
1244fd_turnon(fd_p fd)
1245{
1246 if(!(fd->flags & FD_MOTOR))
1247 {
1248 fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT);
1249 set_motor(fd->fdc, fd->fdsu, TURNON);
1250 timeout(fd_motor_on, fd, hz); /* in 1 sec its ok */
1251 }
1252}
1253
1254static void
1255fdc_reset(fdc_p fdc)
1256{
1257 /* Try a reset, keep motor on */
1258 fdout_wr(fdc, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
1259 TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
1260 DELAY(100);
1261 /* enable FDC, but defer interrupts a moment */
1262 fdout_wr(fdc, fdc->fdout & ~FDO_FDMAEN);
1263 TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN);
1264 DELAY(100);
1265 fdout_wr(fdc, fdc->fdout);
1266 TRACE1("[0x%x->FDOUT]", fdc->fdout);
1267
1268 /* XXX after a reset, silently believe the FDC will accept commands */
1269 (void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
1270 NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
1271 0);
1272 if (fdc->flags & FDC_HAS_FIFO)
1273 (void) enable_fifo(fdc);
1274}
1275
1276/****************************************************************************/
1277/* fdc in/out */
1278/****************************************************************************/
1279int
1280in_fdc(struct fdc_data *fdc)
1281{
1282 int i, j = 100000;
1283 while ((i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM))
1284 != (NE7_DIO|NE7_RQM) && j-- > 0)
1285 if (i == NE7_RQM)
1286 return fdc_err(fdc, "ready for output in input\n");
1287 if (j <= 0)
1288 return fdc_err(fdc, bootverbose? "input ready timeout\n": 0);
1289#ifdef FDC_DEBUG
1290 i = fddata_rd(fdc);
1291 TRACE1("[FDDATA->0x%x]", (unsigned char)i);
1292 return(i);
1293#else /* !FDC_DEBUG */
1294 return fddata_rd(fdc);
1295#endif /* FDC_DEBUG */
1296}
1297
1298/*
1299 * fd_in: Like in_fdc, but allows you to see if it worked.
1300 */
1301static int
1302fd_in(struct fdc_data *fdc, int *ptr)
1303{
1304 int i, j = 100000;
1305 while ((i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM))
1306 != (NE7_DIO|NE7_RQM) && j-- > 0)
1307 if (i == NE7_RQM)
1308 return fdc_err(fdc, "ready for output in input\n");
1309 if (j <= 0)
1310 return fdc_err(fdc, bootverbose? "input ready timeout\n": 0);
1311#ifdef FDC_DEBUG
1312 i = fddata_rd(fdc);
1313 TRACE1("[FDDATA->0x%x]", (unsigned char)i);
1314 *ptr = i;
1315 return 0;
1316#else /* !FDC_DEBUG */
1317 i = fddata_rd(fdc);
1318 if (ptr)
1319 *ptr = i;
1320 return 0;
1321#endif /* FDC_DEBUG */
1322}
1323
1324int
1325out_fdc(struct fdc_data *fdc, int x)
1326{
1327 int i;
1328
1329 /* Check that the direction bit is set */
1330 i = 100000;
1331 while ((fdsts_rd(fdc) & NE7_DIO) && i-- > 0);
1332 if (i <= 0) return fdc_err(fdc, "direction bit not set\n");
1333
1334 /* Check that the floppy controller is ready for a command */
1335 i = 100000;
1336 while ((fdsts_rd(fdc) & NE7_RQM) == 0 && i-- > 0);
1337 if (i <= 0)
1338 return fdc_err(fdc, bootverbose? "output ready timeout\n": 0);
1339
1340 /* Send the command and return */
1341 fddata_wr(fdc, x);
1342 TRACE1("[0x%x->FDDATA]", x);
1343 return (0);
1344}
1345
1346/****************************************************************************/
1347/* fdopen/fdclose */
1348/****************************************************************************/
1349int
1350Fdopen(dev_t dev, int flags, int mode, struct proc *p)
1351{
1352 fdu_t fdu = FDUNIT(minor(dev));
1353 int type = FDTYPE(minor(dev));
1354 fd_p fd;
1355 fdc_p fdc;
1356
1357 /* check bounds */
1358 if ((fd = devclass_get_softc(fd_devclass, fdu)) == 0)
1359 return (ENXIO);
1360 fdc = fd->fdc;
1361 if ((fdc == NULL) || (fd->type == NO_TYPE))
1362 return (ENXIO);
1363 if (type > NUMDENS)
1364 return (ENXIO);
1365 if (type == 0)
1366 type = fd->type;
1367 else {
1368 /*
1369 * For each type of basic drive, make sure we are trying
1370 * to open a type it can do,
1371 */
1372 if (type != fd->type) {
1373 switch (fd->type) {
1374 case FD_360:
1375 return (ENXIO);
1376 case FD_720:
1377 if ( type != FD_820
1378 && type != FD_800
1379 && type != FD_640
1380 )
1381 return (ENXIO);
1382 break;
1383 case FD_1200:
1384 switch (type) {
1385 case FD_1480:
1386 type = FD_1480in5_25;
1387 break;
1388 case FD_1440:
1389 type = FD_1440in5_25;
1390 break;
1391 case FD_1232:
1392 break;
1393 case FD_820:
1394 type = FD_820in5_25;
1395 break;
1396 case FD_800:
1397 type = FD_800in5_25;
1398 break;
1399 case FD_720:
1400 type = FD_720in5_25;
1401 break;
1402 case FD_640:
1403 type = FD_640in5_25;
1404 break;
1405 case FD_360:
1406 type = FD_360in5_25;
1407 break;
1408 default:
1409 return(ENXIO);
1410 }
1411 break;
1412 case FD_1440:
1413 if ( type != FD_1720
1414 && type != FD_1480
1415 && type != FD_1200
1416 && type != FD_820
1417 && type != FD_800
1418 && type != FD_720
1419 && type != FD_640
1420 )
1421 return(ENXIO);
1422 break;
1423 }
1424 }
1425 }
1426 fd->ft = fd_types + type - 1;
1427 fd->flags |= FD_OPEN;
1428
1429 return 0;
1430}
1431
1432int
1433fdclose(dev_t dev, int flags, int mode, struct proc *p)
1434{
1435 fdu_t fdu = FDUNIT(minor(dev));
1436 struct fd_data *fd;
1437
1438 fd = devclass_get_softc(fd_devclass, fdu);
1439 fd->flags &= ~FD_OPEN;
1440 fd->options &= ~FDOPT_NORETRY;
1441
1442 return (0);
1443}
1444
1445/****************************************************************************/
1446/* fdstrategy */
1447/****************************************************************************/
1448void
1450fdstrategy(struct buf *bp)
1449fdstrategy(struct bio *bp)
1451{
1452 unsigned nblocks, blknum, cando;
1453 int s;
1454 fdu_t fdu;
1455 fdc_p fdc;
1456 fd_p fd;
1457 size_t fdblk;
1458
1450{
1451 unsigned nblocks, blknum, cando;
1452 int s;
1453 fdu_t fdu;
1454 fdc_p fdc;
1455 fd_p fd;
1456 size_t fdblk;
1457
1459 fdu = FDUNIT(minor(bp->b_dev));
1458 fdu = FDUNIT(minor(bp->bio_dev));
1460 fd = devclass_get_softc(fd_devclass, fdu);
1461 if (fd == 0)
1462 panic("fdstrategy: buf for nonexistent device (%#lx, %#lx)",
1459 fd = devclass_get_softc(fd_devclass, fdu);
1460 if (fd == 0)
1461 panic("fdstrategy: buf for nonexistent device (%#lx, %#lx)",
1463 (u_long)major(bp->b_dev), (u_long)minor(bp->b_dev));
1462 (u_long)major(bp->bio_dev), (u_long)minor(bp->bio_dev));
1464 fdc = fd->fdc;
1465 if (fd->type == NO_TYPE) {
1463 fdc = fd->fdc;
1464 if (fd->type == NO_TYPE) {
1466 bp->b_error = ENXIO;
1467 bp->b_ioflags |= BIO_ERROR;
1465 bp->bio_error = ENXIO;
1466 bp->bio_flags |= BIO_ERROR;
1468 goto bad;
1469 };
1470
1471 fdblk = 128 << (fd->ft->secsize);
1467 goto bad;
1468 };
1469
1470 fdblk = 128 << (fd->ft->secsize);
1472 if (!(bp->b_flags & B_FORMAT)) {
1473 if (bp->b_blkno < 0) {
1471 if (!(bp->bio_cmd & BIO_FORMAT)) {
1472 if (bp->bio_blkno < 0) {
1474 printf(
1475 "fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n",
1473 printf(
1474 "fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n",
1476 fdu, (u_long)bp->b_blkno, bp->b_bcount);
1477 bp->b_error = EINVAL;
1478 bp->b_ioflags |= BIO_ERROR;
1475 fdu, (u_long)bp->bio_blkno, bp->bio_bcount);
1476 bp->bio_error = EINVAL;
1477 bp->bio_flags |= BIO_ERROR;
1479 goto bad;
1480 }
1478 goto bad;
1479 }
1481 if ((bp->b_bcount % fdblk) != 0) {
1482 bp->b_error = EINVAL;
1483 bp->b_ioflags |= BIO_ERROR;
1480 if ((bp->bio_bcount % fdblk) != 0) {
1481 bp->bio_error = EINVAL;
1482 bp->bio_flags |= BIO_ERROR;
1484 goto bad;
1485 }
1486 }
1487
1488 /*
1489 * Set up block calculations.
1490 */
1483 goto bad;
1484 }
1485 }
1486
1487 /*
1488 * Set up block calculations.
1489 */
1491 if (bp->b_blkno > 20000000) {
1490 if (bp->bio_blkno > 20000000) {
1492 /*
1493 * Reject unreasonably high block number, prevent the
1494 * multiplication below from overflowing.
1495 */
1491 /*
1492 * Reject unreasonably high block number, prevent the
1493 * multiplication below from overflowing.
1494 */
1496 bp->b_error = EINVAL;
1497 bp->b_ioflags |= BIO_ERROR;
1495 bp->bio_error = EINVAL;
1496 bp->bio_flags |= BIO_ERROR;
1498 goto bad;
1499 }
1497 goto bad;
1498 }
1500 blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk;
1499 blknum = (unsigned) bp->bio_blkno * DEV_BSIZE/fdblk;
1501 nblocks = fd->ft->size;
1500 nblocks = fd->ft->size;
1502 bp->b_resid = 0;
1503 if (blknum + (bp->b_bcount / fdblk) > nblocks) {
1501 bp->bio_resid = 0;
1502 if (blknum + (bp->bio_bcount / fdblk) > nblocks) {
1504 if (blknum <= nblocks) {
1505 cando = (nblocks - blknum) * fdblk;
1503 if (blknum <= nblocks) {
1504 cando = (nblocks - blknum) * fdblk;
1506 bp->b_resid = bp->b_bcount - cando;
1505 bp->bio_resid = bp->bio_bcount - cando;
1507 if (cando == 0)
1508 goto bad; /* not actually bad but EOF */
1509 } else {
1506 if (cando == 0)
1507 goto bad; /* not actually bad but EOF */
1508 } else {
1510 bp->b_error = EINVAL;
1511 bp->b_ioflags |= BIO_ERROR;
1509 bp->bio_error = EINVAL;
1510 bp->bio_flags |= BIO_ERROR;
1512 goto bad;
1513 }
1514 }
1511 goto bad;
1512 }
1513 }
1515 bp->b_pblkno = bp->b_blkno;
1514 bp->bio_pblkno = bp->bio_blkno;
1516 s = splbio();
1515 s = splbio();
1517 bufqdisksort(&fdc->head, bp);
1516 bioqdisksort(&fdc->head, bp);
1518 untimeout(fd_turnoff, fd, fd->toffhandle); /* a good idea */
1519
1520 /* Tell devstat we are starting on the transaction */
1521 devstat_start_transaction(&fd->device_stats);
1522 device_busy(fd->dev);
1523
1524 fdstart(fdc);
1525 splx(s);
1526 return;
1527
1528bad:
1529 biodone(bp);
1530}
1531
1532/***************************************************************\
1533* fdstart *
1534* We have just queued something.. if the controller is not busy *
1535* then simulate the case where it has just finished a command *
1536* So that it (the interrupt routine) looks on the queue for more*
1537* work to do and picks up what we just added. *
1538* If the controller is already busy, we need do nothing, as it *
1539* will pick up our work when the present work completes *
1540\***************************************************************/
1541static void
1542fdstart(struct fdc_data *fdc)
1543{
1544 int s;
1545
1546 s = splbio();
1547 if(fdc->state == DEVIDLE)
1548 {
1549 fdc_intr(fdc);
1550 }
1551 splx(s);
1552}
1553
1554static void
1555fd_iotimeout(void *xfdc)
1556{
1557 fdc_p fdc;
1558 int s;
1559
1560 fdc = xfdc;
1561 TRACE1("fd%d[fd_iotimeout()]", fdc->fdu);
1562
1563 /*
1564 * Due to IBM's brain-dead design, the FDC has a faked ready
1565 * signal, hardwired to ready == true. Thus, any command
1566 * issued if there's no diskette in the drive will _never_
1567 * complete, and must be aborted by resetting the FDC.
1568 * Many thanks, Big Blue!
1569 * The FDC must not be reset directly, since that would
1570 * interfere with the state machine. Instead, pretend that
1571 * the command completed but was invalid. The state machine
1572 * will reset the FDC and retry once.
1573 */
1574 s = splbio();
1575 fdc->status[0] = NE7_ST0_IC_IV;
1576 fdc->flags &= ~FDC_STAT_VALID;
1577 fdc->state = IOTIMEDOUT;
1578 fdc_intr(fdc);
1579 splx(s);
1580}
1581
1582/* just ensure it has the right spl */
1583static void
1584fd_pseudointr(void *xfdc)
1585{
1586 int s;
1587
1588 s = splbio();
1589 fdc_intr(xfdc);
1590 splx(s);
1591}
1592
1593/***********************************************************************\
1594* fdintr *
1595* keep calling the state machine until it returns a 0 *
1596* ALWAYS called at SPLBIO *
1597\***********************************************************************/
1598static void
1599fdc_intr(void *xfdc)
1600{
1601 fdc_p fdc = xfdc;
1602 while(fdstate(fdc))
1603 ;
1604}
1605
1606/*
1607 * magic pseudo-DMA initialization for YE FDC. Sets count and
1608 * direction
1609 */
1610#define SET_BCDR(fdc,wr,cnt,port) \
1611 bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port, \
1612 ((cnt)-1) & 0xff); \
1613 bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port + 1, \
1614 ((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f)));
1615
1616/*
1617 * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy
1618 */
1619static int fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
1620{
1621 u_char *cptr = (u_char *)addr;
1622
1623 if (flags == BIO_READ) {
1624 if (fdc->state != PIOREAD) {
1625 fdc->state = PIOREAD;
1626 return(0);
1627 };
1628 SET_BCDR(fdc, 0, count, 0);
1629 bus_space_read_multi_1(fdc->portt, fdc->porth, fdc->port_off +
1630 FDC_YE_DATAPORT, cptr, count);
1631 } else {
1632 bus_space_write_multi_1(fdc->portt, fdc->porth, fdc->port_off +
1633 FDC_YE_DATAPORT, cptr, count);
1634 SET_BCDR(fdc, 0, count, 0);
1635 };
1636 return(1);
1637}
1638
1639/***********************************************************************\
1640* The controller state machine. *
1641* if it returns a non zero value, it should be called again immediatly *
1642\***********************************************************************/
1643static int
1644fdstate(fdc_p fdc)
1645{
1646 int read, format, head, i, sec = 0, sectrac, st0, cyl, st3, idf;
1647 unsigned blknum = 0, b_cylinder = 0;
1648 fdu_t fdu = fdc->fdu;
1649 fd_p fd;
1517 untimeout(fd_turnoff, fd, fd->toffhandle); /* a good idea */
1518
1519 /* Tell devstat we are starting on the transaction */
1520 devstat_start_transaction(&fd->device_stats);
1521 device_busy(fd->dev);
1522
1523 fdstart(fdc);
1524 splx(s);
1525 return;
1526
1527bad:
1528 biodone(bp);
1529}
1530
1531/***************************************************************\
1532* fdstart *
1533* We have just queued something.. if the controller is not busy *
1534* then simulate the case where it has just finished a command *
1535* So that it (the interrupt routine) looks on the queue for more*
1536* work to do and picks up what we just added. *
1537* If the controller is already busy, we need do nothing, as it *
1538* will pick up our work when the present work completes *
1539\***************************************************************/
1540static void
1541fdstart(struct fdc_data *fdc)
1542{
1543 int s;
1544
1545 s = splbio();
1546 if(fdc->state == DEVIDLE)
1547 {
1548 fdc_intr(fdc);
1549 }
1550 splx(s);
1551}
1552
1553static void
1554fd_iotimeout(void *xfdc)
1555{
1556 fdc_p fdc;
1557 int s;
1558
1559 fdc = xfdc;
1560 TRACE1("fd%d[fd_iotimeout()]", fdc->fdu);
1561
1562 /*
1563 * Due to IBM's brain-dead design, the FDC has a faked ready
1564 * signal, hardwired to ready == true. Thus, any command
1565 * issued if there's no diskette in the drive will _never_
1566 * complete, and must be aborted by resetting the FDC.
1567 * Many thanks, Big Blue!
1568 * The FDC must not be reset directly, since that would
1569 * interfere with the state machine. Instead, pretend that
1570 * the command completed but was invalid. The state machine
1571 * will reset the FDC and retry once.
1572 */
1573 s = splbio();
1574 fdc->status[0] = NE7_ST0_IC_IV;
1575 fdc->flags &= ~FDC_STAT_VALID;
1576 fdc->state = IOTIMEDOUT;
1577 fdc_intr(fdc);
1578 splx(s);
1579}
1580
1581/* just ensure it has the right spl */
1582static void
1583fd_pseudointr(void *xfdc)
1584{
1585 int s;
1586
1587 s = splbio();
1588 fdc_intr(xfdc);
1589 splx(s);
1590}
1591
1592/***********************************************************************\
1593* fdintr *
1594* keep calling the state machine until it returns a 0 *
1595* ALWAYS called at SPLBIO *
1596\***********************************************************************/
1597static void
1598fdc_intr(void *xfdc)
1599{
1600 fdc_p fdc = xfdc;
1601 while(fdstate(fdc))
1602 ;
1603}
1604
1605/*
1606 * magic pseudo-DMA initialization for YE FDC. Sets count and
1607 * direction
1608 */
1609#define SET_BCDR(fdc,wr,cnt,port) \
1610 bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port, \
1611 ((cnt)-1) & 0xff); \
1612 bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port + 1, \
1613 ((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f)));
1614
1615/*
1616 * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy
1617 */
1618static int fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
1619{
1620 u_char *cptr = (u_char *)addr;
1621
1622 if (flags == BIO_READ) {
1623 if (fdc->state != PIOREAD) {
1624 fdc->state = PIOREAD;
1625 return(0);
1626 };
1627 SET_BCDR(fdc, 0, count, 0);
1628 bus_space_read_multi_1(fdc->portt, fdc->porth, fdc->port_off +
1629 FDC_YE_DATAPORT, cptr, count);
1630 } else {
1631 bus_space_write_multi_1(fdc->portt, fdc->porth, fdc->port_off +
1632 FDC_YE_DATAPORT, cptr, count);
1633 SET_BCDR(fdc, 0, count, 0);
1634 };
1635 return(1);
1636}
1637
1638/***********************************************************************\
1639* The controller state machine. *
1640* if it returns a non zero value, it should be called again immediatly *
1641\***********************************************************************/
1642static int
1643fdstate(fdc_p fdc)
1644{
1645 int read, format, head, i, sec = 0, sectrac, st0, cyl, st3, idf;
1646 unsigned blknum = 0, b_cylinder = 0;
1647 fdu_t fdu = fdc->fdu;
1648 fd_p fd;
1650 register struct buf *bp;
1649 register struct bio *bp;
1651 struct fd_formb *finfo = NULL;
1652 size_t fdblk;
1653
1654 bp = fdc->bp;
1655 if (bp == NULL) {
1650 struct fd_formb *finfo = NULL;
1651 size_t fdblk;
1652
1653 bp = fdc->bp;
1654 if (bp == NULL) {
1656 bp = bufq_first(&fdc->head);
1655 bp = bioq_first(&fdc->head);
1657 if (bp != NULL) {
1656 if (bp != NULL) {
1658 bufq_remove(&fdc->head, bp);
1657 bioq_remove(&fdc->head, bp);
1659 fdc->bp = bp;
1660 }
1661 }
1662 if (bp == NULL) {
1663 /***********************************************\
1664 * nothing left for this controller to do *
1665 * Force into the IDLE state, *
1666 \***********************************************/
1667 fdc->state = DEVIDLE;
1668 if (fdc->fd) {
1669 device_printf(fdc->fdc_dev,
1670 "unexpected valid fd pointer\n");
1671 fdc->fd = (fd_p) 0;
1672 fdc->fdu = -1;
1673 }
1674 TRACE1("[fdc%d IDLE]", fdc->fdcu);
1675 return (0);
1676 }
1658 fdc->bp = bp;
1659 }
1660 }
1661 if (bp == NULL) {
1662 /***********************************************\
1663 * nothing left for this controller to do *
1664 * Force into the IDLE state, *
1665 \***********************************************/
1666 fdc->state = DEVIDLE;
1667 if (fdc->fd) {
1668 device_printf(fdc->fdc_dev,
1669 "unexpected valid fd pointer\n");
1670 fdc->fd = (fd_p) 0;
1671 fdc->fdu = -1;
1672 }
1673 TRACE1("[fdc%d IDLE]", fdc->fdcu);
1674 return (0);
1675 }
1677 fdu = FDUNIT(minor(bp->b_dev));
1676 fdu = FDUNIT(minor(bp->bio_dev));
1678 fd = devclass_get_softc(fd_devclass, fdu);
1679 fdblk = 128 << fd->ft->secsize;
1680 if (fdc->fd && (fd != fdc->fd))
1681 device_printf(fd->dev, "confused fd pointers\n");
1677 fd = devclass_get_softc(fd_devclass, fdu);
1678 fdblk = 128 << fd->ft->secsize;
1679 if (fdc->fd && (fd != fdc->fd))
1680 device_printf(fd->dev, "confused fd pointers\n");
1682 read = bp->b_iocmd == BIO_READ;
1681 read = bp->bio_cmd == BIO_READ;
1683 if (read)
1684 idf = ISADMA_READ;
1685 else
1686 idf = ISADMA_WRITE;
1682 if (read)
1683 idf = ISADMA_READ;
1684 else
1685 idf = ISADMA_WRITE;
1687 format = bp->b_flags & B_FORMAT;
1686 format = bp->bio_cmd & BIO_FORMAT;
1688 if (format) {
1687 if (format) {
1689 finfo = (struct fd_formb *)bp->b_data;
1688 finfo = (struct fd_formb *)bp->bio_data;
1690 fd->skip = (char *)&(finfo->fd_formb_cylno(0))
1691 - (char *)finfo;
1692 }
1693 if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) {
1689 fd->skip = (char *)&(finfo->fd_formb_cylno(0))
1690 - (char *)finfo;
1691 }
1692 if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) {
1694 blknum = (unsigned) bp->b_pblkno * DEV_BSIZE/fdblk +
1693 blknum = (unsigned) bp->bio_pblkno * DEV_BSIZE/fdblk +
1695 fd->skip/fdblk;
1696 b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
1697 }
1698 TRACE1("fd%d", fdu);
1699 TRACE1("[%s]", fdstates[fdc->state]);
1700 TRACE1("(0x%x)", fd->flags);
1701 untimeout(fd_turnoff, fd, fd->toffhandle);
1702 fd->toffhandle = timeout(fd_turnoff, fd, 4 * hz);
1703 switch (fdc->state)
1704 {
1705 case DEVIDLE:
1706 case FINDWORK: /* we have found new work */
1707 fdc->retry = 0;
1708 fd->skip = 0;
1709 fdc->fd = fd;
1710 fdc->fdu = fdu;
1711 fdc->fdctl_wr(fdc, fd->ft->trans);
1712 TRACE1("[0x%x->FDCTL]", fd->ft->trans);
1713 /*******************************************************\
1714 * If the next drive has a motor startup pending, then *
1715 * it will start up in its own good time *
1716 \*******************************************************/
1717 if(fd->flags & FD_MOTOR_WAIT) {
1718 fdc->state = MOTORWAIT;
1719 return (0); /* come back later */
1720 }
1721 /*******************************************************\
1722 * Maybe if it's not starting, it SHOULD be starting *
1723 \*******************************************************/
1724 if (!(fd->flags & FD_MOTOR))
1725 {
1726 fdc->state = MOTORWAIT;
1727 fd_turnon(fd);
1728 return (0);
1729 }
1730 else /* at least make sure we are selected */
1731 {
1732 set_motor(fdc, fd->fdsu, TURNON);
1733 }
1734 if (fdc->flags & FDC_NEEDS_RESET) {
1735 fdc->state = RESETCTLR;
1736 fdc->flags &= ~FDC_NEEDS_RESET;
1737 } else
1738 fdc->state = DOSEEK;
1739 break;
1740 case DOSEEK:
1741 if (b_cylinder == (unsigned)fd->track)
1742 {
1743 fdc->state = SEEKCOMPLETE;
1744 break;
1745 }
1746 if (fd_cmd(fdc, 3, NE7CMD_SEEK,
1747 fd->fdsu, b_cylinder * fd->ft->steptrac,
1748 0))
1749 {
1750 /*
1751 * seek command not accepted, looks like
1752 * the FDC went off to the Saints...
1753 */
1754 fdc->retry = 6; /* try a reset */
1755 return(retrier(fdc));
1756 }
1757 fd->track = FD_NO_TRACK;
1758 fdc->state = SEEKWAIT;
1759 return(0); /* will return later */
1760 case SEEKWAIT:
1761 /* allow heads to settle */
1762 timeout(fd_pseudointr, fdc, hz / 16);
1763 fdc->state = SEEKCOMPLETE;
1764 return(0); /* will return later */
1765 case SEEKCOMPLETE : /* SEEK DONE, START DMA */
1766 /* Make sure seek really happened*/
1767 if(fd->track == FD_NO_TRACK) {
1768 int descyl = b_cylinder * fd->ft->steptrac;
1769 do {
1770 /*
1771 * This might be a "ready changed" interrupt,
1772 * which cannot really happen since the
1773 * RDY pin is hardwired to + 5 volts. This
1774 * generally indicates a "bouncing" intr
1775 * line, so do one of the following:
1776 *
1777 * When running on an enhanced FDC that is
1778 * known to not go stuck after responding
1779 * with INVALID, fetch all interrupt states
1780 * until seeing either an INVALID or a
1781 * real interrupt condition.
1782 *
1783 * When running on a dumb old NE765, give
1784 * up immediately. The controller will
1785 * provide up to four dummy RC interrupt
1786 * conditions right after reset (for the
1787 * corresponding four drives), so this is
1788 * our only chance to get notice that it
1789 * was not the FDC that caused the interrupt.
1790 */
1791 if (fd_sense_int(fdc, &st0, &cyl)
1792 == FD_NOT_VALID)
1793 return 0;
1794 if(fdc->fdct == FDC_NE765
1795 && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
1796 return 0; /* hope for a real intr */
1797 } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
1798
1799 if (0 == descyl) {
1800 int failed = 0;
1801 /*
1802 * seek to cyl 0 requested; make sure we are
1803 * really there
1804 */
1805 if (fd_sense_drive_status(fdc, &st3))
1806 failed = 1;
1807 if ((st3 & NE7_ST3_T0) == 0) {
1808 printf(
1809 "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n",
1810 fdu, st3, NE7_ST3BITS);
1811 failed = 1;
1812 }
1813
1814 if (failed) {
1815 if(fdc->retry < 3)
1816 fdc->retry = 3;
1817 return (retrier(fdc));
1818 }
1819 }
1820
1821 if (cyl != descyl) {
1822 printf(
1823 "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
1824 fdu, descyl, cyl, st0);
1825 if (fdc->retry < 3)
1826 fdc->retry = 3;
1827 return (retrier(fdc));
1828 }
1829 }
1830
1831 fd->track = b_cylinder;
1832 if (!(fdc->flags & FDC_NODMA))
1694 fd->skip/fdblk;
1695 b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
1696 }
1697 TRACE1("fd%d", fdu);
1698 TRACE1("[%s]", fdstates[fdc->state]);
1699 TRACE1("(0x%x)", fd->flags);
1700 untimeout(fd_turnoff, fd, fd->toffhandle);
1701 fd->toffhandle = timeout(fd_turnoff, fd, 4 * hz);
1702 switch (fdc->state)
1703 {
1704 case DEVIDLE:
1705 case FINDWORK: /* we have found new work */
1706 fdc->retry = 0;
1707 fd->skip = 0;
1708 fdc->fd = fd;
1709 fdc->fdu = fdu;
1710 fdc->fdctl_wr(fdc, fd->ft->trans);
1711 TRACE1("[0x%x->FDCTL]", fd->ft->trans);
1712 /*******************************************************\
1713 * If the next drive has a motor startup pending, then *
1714 * it will start up in its own good time *
1715 \*******************************************************/
1716 if(fd->flags & FD_MOTOR_WAIT) {
1717 fdc->state = MOTORWAIT;
1718 return (0); /* come back later */
1719 }
1720 /*******************************************************\
1721 * Maybe if it's not starting, it SHOULD be starting *
1722 \*******************************************************/
1723 if (!(fd->flags & FD_MOTOR))
1724 {
1725 fdc->state = MOTORWAIT;
1726 fd_turnon(fd);
1727 return (0);
1728 }
1729 else /* at least make sure we are selected */
1730 {
1731 set_motor(fdc, fd->fdsu, TURNON);
1732 }
1733 if (fdc->flags & FDC_NEEDS_RESET) {
1734 fdc->state = RESETCTLR;
1735 fdc->flags &= ~FDC_NEEDS_RESET;
1736 } else
1737 fdc->state = DOSEEK;
1738 break;
1739 case DOSEEK:
1740 if (b_cylinder == (unsigned)fd->track)
1741 {
1742 fdc->state = SEEKCOMPLETE;
1743 break;
1744 }
1745 if (fd_cmd(fdc, 3, NE7CMD_SEEK,
1746 fd->fdsu, b_cylinder * fd->ft->steptrac,
1747 0))
1748 {
1749 /*
1750 * seek command not accepted, looks like
1751 * the FDC went off to the Saints...
1752 */
1753 fdc->retry = 6; /* try a reset */
1754 return(retrier(fdc));
1755 }
1756 fd->track = FD_NO_TRACK;
1757 fdc->state = SEEKWAIT;
1758 return(0); /* will return later */
1759 case SEEKWAIT:
1760 /* allow heads to settle */
1761 timeout(fd_pseudointr, fdc, hz / 16);
1762 fdc->state = SEEKCOMPLETE;
1763 return(0); /* will return later */
1764 case SEEKCOMPLETE : /* SEEK DONE, START DMA */
1765 /* Make sure seek really happened*/
1766 if(fd->track == FD_NO_TRACK) {
1767 int descyl = b_cylinder * fd->ft->steptrac;
1768 do {
1769 /*
1770 * This might be a "ready changed" interrupt,
1771 * which cannot really happen since the
1772 * RDY pin is hardwired to + 5 volts. This
1773 * generally indicates a "bouncing" intr
1774 * line, so do one of the following:
1775 *
1776 * When running on an enhanced FDC that is
1777 * known to not go stuck after responding
1778 * with INVALID, fetch all interrupt states
1779 * until seeing either an INVALID or a
1780 * real interrupt condition.
1781 *
1782 * When running on a dumb old NE765, give
1783 * up immediately. The controller will
1784 * provide up to four dummy RC interrupt
1785 * conditions right after reset (for the
1786 * corresponding four drives), so this is
1787 * our only chance to get notice that it
1788 * was not the FDC that caused the interrupt.
1789 */
1790 if (fd_sense_int(fdc, &st0, &cyl)
1791 == FD_NOT_VALID)
1792 return 0;
1793 if(fdc->fdct == FDC_NE765
1794 && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
1795 return 0; /* hope for a real intr */
1796 } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
1797
1798 if (0 == descyl) {
1799 int failed = 0;
1800 /*
1801 * seek to cyl 0 requested; make sure we are
1802 * really there
1803 */
1804 if (fd_sense_drive_status(fdc, &st3))
1805 failed = 1;
1806 if ((st3 & NE7_ST3_T0) == 0) {
1807 printf(
1808 "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n",
1809 fdu, st3, NE7_ST3BITS);
1810 failed = 1;
1811 }
1812
1813 if (failed) {
1814 if(fdc->retry < 3)
1815 fdc->retry = 3;
1816 return (retrier(fdc));
1817 }
1818 }
1819
1820 if (cyl != descyl) {
1821 printf(
1822 "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
1823 fdu, descyl, cyl, st0);
1824 if (fdc->retry < 3)
1825 fdc->retry = 3;
1826 return (retrier(fdc));
1827 }
1828 }
1829
1830 fd->track = b_cylinder;
1831 if (!(fdc->flags & FDC_NODMA))
1833 isa_dmastart(idf, bp->b_data+fd->skip,
1834 format ? bp->b_bcount : fdblk, fdc->dmachan);
1832 isa_dmastart(idf, bp->bio_data+fd->skip,
1833 format ? bp->bio_bcount : fdblk, fdc->dmachan);
1835 sectrac = fd->ft->sectrac;
1836 sec = blknum % (sectrac * fd->ft->heads);
1837 head = sec / sectrac;
1838 sec = sec % sectrac + 1;
1839 fd->hddrv = ((head&1)<<2)+fdu;
1840
1841 if(format || !read)
1842 {
1843 /* make sure the drive is writable */
1844 if(fd_sense_drive_status(fdc, &st3) != 0)
1845 {
1846 /* stuck controller? */
1847 if (!(fdc->flags & FDC_NODMA))
1848 isa_dmadone(idf,
1834 sectrac = fd->ft->sectrac;
1835 sec = blknum % (sectrac * fd->ft->heads);
1836 head = sec / sectrac;
1837 sec = sec % sectrac + 1;
1838 fd->hddrv = ((head&1)<<2)+fdu;
1839
1840 if(format || !read)
1841 {
1842 /* make sure the drive is writable */
1843 if(fd_sense_drive_status(fdc, &st3) != 0)
1844 {
1845 /* stuck controller? */
1846 if (!(fdc->flags & FDC_NODMA))
1847 isa_dmadone(idf,
1849 bp->b_data + fd->skip,
1850 format ? bp->b_bcount : fdblk,
1848 bp->bio_data + fd->skip,
1849 format ? bp->bio_bcount : fdblk,
1851 fdc->dmachan);
1852 fdc->retry = 6; /* reset the beast */
1853 return (retrier(fdc));
1854 }
1855 if(st3 & NE7_ST3_WP)
1856 {
1857 /*
1858 * XXX YES! this is ugly.
1859 * in order to force the current operation
1860 * to fail, we will have to fake an FDC
1861 * error - all error handling is done
1862 * by the retrier()
1863 */
1864 fdc->status[0] = NE7_ST0_IC_AT;
1865 fdc->status[1] = NE7_ST1_NW;
1866 fdc->status[2] = 0;
1867 fdc->status[3] = fd->track;
1868 fdc->status[4] = head;
1869 fdc->status[5] = sec;
1870 fdc->retry = 8; /* break out immediately */
1871 fdc->state = IOTIMEDOUT; /* not really... */
1872 return (1);
1873 }
1874 }
1875
1876 if (format) {
1877 if (fdc->flags & FDC_NODMA) {
1878 /*
1879 * This seems to be necessary for
1880 * whatever obscure reason; if we omit
1881 * it, we end up filling the sector ID
1882 * fields of the newly formatted track
1883 * entirely with garbage, causing
1884 * `wrong cylinder' errors all over
1885 * the place when trying to read them
1886 * back.
1887 *
1888 * Umpf.
1889 */
1850 fdc->dmachan);
1851 fdc->retry = 6; /* reset the beast */
1852 return (retrier(fdc));
1853 }
1854 if(st3 & NE7_ST3_WP)
1855 {
1856 /*
1857 * XXX YES! this is ugly.
1858 * in order to force the current operation
1859 * to fail, we will have to fake an FDC
1860 * error - all error handling is done
1861 * by the retrier()
1862 */
1863 fdc->status[0] = NE7_ST0_IC_AT;
1864 fdc->status[1] = NE7_ST1_NW;
1865 fdc->status[2] = 0;
1866 fdc->status[3] = fd->track;
1867 fdc->status[4] = head;
1868 fdc->status[5] = sec;
1869 fdc->retry = 8; /* break out immediately */
1870 fdc->state = IOTIMEDOUT; /* not really... */
1871 return (1);
1872 }
1873 }
1874
1875 if (format) {
1876 if (fdc->flags & FDC_NODMA) {
1877 /*
1878 * This seems to be necessary for
1879 * whatever obscure reason; if we omit
1880 * it, we end up filling the sector ID
1881 * fields of the newly formatted track
1882 * entirely with garbage, causing
1883 * `wrong cylinder' errors all over
1884 * the place when trying to read them
1885 * back.
1886 *
1887 * Umpf.
1888 */
1890 SET_BCDR(fdc, 1, bp->b_bcount, 0);
1889 SET_BCDR(fdc, 1, bp->bio_bcount, 0);
1891
1890
1892 (void)fdcpio(fdc,bp->b_iocmd,
1893 bp->b_data+fd->skip,
1894 bp->b_bcount);
1891 (void)fdcpio(fdc,bp->bio_cmd,
1892 bp->bio_data+fd->skip,
1893 bp->bio_bcount);
1895
1896 }
1897 /* formatting */
1898 if(fd_cmd(fdc, 6, NE7CMD_FORMAT, head << 2 | fdu,
1899 finfo->fd_formb_secshift,
1900 finfo->fd_formb_nsecs,
1901 finfo->fd_formb_gaplen,
1902 finfo->fd_formb_fillbyte, 0)) {
1903 /* controller fell over */
1904 if (!(fdc->flags & FDC_NODMA))
1905 isa_dmadone(idf,
1894
1895 }
1896 /* formatting */
1897 if(fd_cmd(fdc, 6, NE7CMD_FORMAT, head << 2 | fdu,
1898 finfo->fd_formb_secshift,
1899 finfo->fd_formb_nsecs,
1900 finfo->fd_formb_gaplen,
1901 finfo->fd_formb_fillbyte, 0)) {
1902 /* controller fell over */
1903 if (!(fdc->flags & FDC_NODMA))
1904 isa_dmadone(idf,
1906 bp->b_data + fd->skip,
1907 format ? bp->b_bcount : fdblk,
1905 bp->bio_data + fd->skip,
1906 format ? bp->bio_bcount : fdblk,
1908 fdc->dmachan);
1909 fdc->retry = 6;
1910 return (retrier(fdc));
1911 }
1912 } else {
1913 if (fdc->flags & FDC_NODMA) {
1914 /*
1915 * this seems to be necessary even when
1916 * reading data
1917 */
1918 SET_BCDR(fdc, 1, fdblk, 0);
1919
1920 /*
1921 * perform the write pseudo-DMA before
1922 * the WRITE command is sent
1923 */
1924 if (!read)
1907 fdc->dmachan);
1908 fdc->retry = 6;
1909 return (retrier(fdc));
1910 }
1911 } else {
1912 if (fdc->flags & FDC_NODMA) {
1913 /*
1914 * this seems to be necessary even when
1915 * reading data
1916 */
1917 SET_BCDR(fdc, 1, fdblk, 0);
1918
1919 /*
1920 * perform the write pseudo-DMA before
1921 * the WRITE command is sent
1922 */
1923 if (!read)
1925 (void)fdcpio(fdc,bp->b_iocmd,
1926 bp->b_data+fd->skip,
1924 (void)fdcpio(fdc,bp->bio_cmd,
1925 bp->bio_data+fd->skip,
1927 fdblk);
1928 }
1929 if (fd_cmd(fdc, 9,
1930 (read ? NE7CMD_READ : NE7CMD_WRITE),
1931 head << 2 | fdu, /* head & unit */
1932 fd->track, /* track */
1933 head,
1934 sec, /* sector + 1 */
1935 fd->ft->secsize, /* sector size */
1936 sectrac, /* sectors/track */
1937 fd->ft->gap, /* gap size */
1938 fd->ft->datalen, /* data length */
1939 0)) {
1940 /* the beast is sleeping again */
1941 if (!(fdc->flags & FDC_NODMA))
1942 isa_dmadone(idf,
1926 fdblk);
1927 }
1928 if (fd_cmd(fdc, 9,
1929 (read ? NE7CMD_READ : NE7CMD_WRITE),
1930 head << 2 | fdu, /* head & unit */
1931 fd->track, /* track */
1932 head,
1933 sec, /* sector + 1 */
1934 fd->ft->secsize, /* sector size */
1935 sectrac, /* sectors/track */
1936 fd->ft->gap, /* gap size */
1937 fd->ft->datalen, /* data length */
1938 0)) {
1939 /* the beast is sleeping again */
1940 if (!(fdc->flags & FDC_NODMA))
1941 isa_dmadone(idf,
1943 bp->b_data + fd->skip,
1944 format ? bp->b_bcount : fdblk,
1942 bp->bio_data + fd->skip,
1943 format ? bp->bio_bcount : fdblk,
1945 fdc->dmachan);
1946 fdc->retry = 6;
1947 return (retrier(fdc));
1948 }
1949 }
1950 if (fdc->flags & FDC_NODMA)
1951 /*
1952 * if this is a read, then simply await interrupt
1953 * before performing PIO
1954 */
1944 fdc->dmachan);
1945 fdc->retry = 6;
1946 return (retrier(fdc));
1947 }
1948 }
1949 if (fdc->flags & FDC_NODMA)
1950 /*
1951 * if this is a read, then simply await interrupt
1952 * before performing PIO
1953 */
1955 if (read && !fdcpio(fdc,bp->b_iocmd,
1956 bp->b_data+fd->skip,fdblk)) {
1954 if (read && !fdcpio(fdc,bp->bio_cmd,
1955 bp->bio_data+fd->skip,fdblk)) {
1957 fd->tohandle = timeout(fd_iotimeout, fdc, hz);
1958 return(0); /* will return later */
1959 };
1960
1961 /*
1962 * write (or format) operation will fall through and
1963 * await completion interrupt
1964 */
1965 fdc->state = IOCOMPLETE;
1966 fd->tohandle = timeout(fd_iotimeout, fdc, hz);
1967 return (0); /* will return later */
1968 case PIOREAD:
1969 /*
1970 * actually perform the PIO read. The IOCOMPLETE case
1971 * removes the timeout for us.
1972 */
1956 fd->tohandle = timeout(fd_iotimeout, fdc, hz);
1957 return(0); /* will return later */
1958 };
1959
1960 /*
1961 * write (or format) operation will fall through and
1962 * await completion interrupt
1963 */
1964 fdc->state = IOCOMPLETE;
1965 fd->tohandle = timeout(fd_iotimeout, fdc, hz);
1966 return (0); /* will return later */
1967 case PIOREAD:
1968 /*
1969 * actually perform the PIO read. The IOCOMPLETE case
1970 * removes the timeout for us.
1971 */
1973 (void)fdcpio(fdc,bp->b_iocmd,bp->b_data+fd->skip,fdblk);
1972 (void)fdcpio(fdc,bp->bio_cmd,bp->bio_data+fd->skip,fdblk);
1974 fdc->state = IOCOMPLETE;
1975 /* FALLTHROUGH */
1976 case IOCOMPLETE: /* IO DONE, post-analyze */
1977 untimeout(fd_iotimeout, fdc, fd->tohandle);
1978
1979 if (fd_read_status(fdc, fd->fdsu)) {
1980 if (!(fdc->flags & FDC_NODMA))
1973 fdc->state = IOCOMPLETE;
1974 /* FALLTHROUGH */
1975 case IOCOMPLETE: /* IO DONE, post-analyze */
1976 untimeout(fd_iotimeout, fdc, fd->tohandle);
1977
1978 if (fd_read_status(fdc, fd->fdsu)) {
1979 if (!(fdc->flags & FDC_NODMA))
1981 isa_dmadone(idf, bp->b_data + fd->skip,
1982 format ? bp->b_bcount : fdblk,
1980 isa_dmadone(idf, bp->bio_data + fd->skip,
1981 format ? bp->bio_bcount : fdblk,
1983 fdc->dmachan);
1984 if (fdc->retry < 6)
1985 fdc->retry = 6; /* force a reset */
1986 return (retrier(fdc));
1987 }
1988
1989 fdc->state = IOTIMEDOUT;
1990
1991 /* FALLTHROUGH */
1992
1993 case IOTIMEDOUT:
1994 if (!(fdc->flags & FDC_NODMA))
1982 fdc->dmachan);
1983 if (fdc->retry < 6)
1984 fdc->retry = 6; /* force a reset */
1985 return (retrier(fdc));
1986 }
1987
1988 fdc->state = IOTIMEDOUT;
1989
1990 /* FALLTHROUGH */
1991
1992 case IOTIMEDOUT:
1993 if (!(fdc->flags & FDC_NODMA))
1995 isa_dmadone(idf, bp->b_data + fd->skip,
1996 format ? bp->b_bcount : fdblk, fdc->dmachan);
1994 isa_dmadone(idf, bp->bio_data + fd->skip,
1995 format ? bp->bio_bcount : fdblk, fdc->dmachan);
1997 if (fdc->status[0] & NE7_ST0_IC) {
1998 if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
1999 && fdc->status[1] & NE7_ST1_OR) {
2000 /*
2001 * DMA overrun. Someone hogged the bus
2002 * and didn't release it in time for the
2003 * next FDC transfer.
2004 * Just restart it, don't increment retry
2005 * count. (vak)
2006 */
2007 fdc->state = SEEKCOMPLETE;
2008 return (1);
2009 }
2010 else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV
2011 && fdc->retry < 6)
2012 fdc->retry = 6; /* force a reset */
2013 else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
2014 && fdc->status[2] & NE7_ST2_WC
2015 && fdc->retry < 3)
2016 fdc->retry = 3; /* force recalibrate */
2017 return (retrier(fdc));
2018 }
2019 /* All OK */
2020 fd->skip += fdblk;
1996 if (fdc->status[0] & NE7_ST0_IC) {
1997 if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
1998 && fdc->status[1] & NE7_ST1_OR) {
1999 /*
2000 * DMA overrun. Someone hogged the bus
2001 * and didn't release it in time for the
2002 * next FDC transfer.
2003 * Just restart it, don't increment retry
2004 * count. (vak)
2005 */
2006 fdc->state = SEEKCOMPLETE;
2007 return (1);
2008 }
2009 else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV
2010 && fdc->retry < 6)
2011 fdc->retry = 6; /* force a reset */
2012 else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
2013 && fdc->status[2] & NE7_ST2_WC
2014 && fdc->retry < 3)
2015 fdc->retry = 3; /* force recalibrate */
2016 return (retrier(fdc));
2017 }
2018 /* All OK */
2019 fd->skip += fdblk;
2021 if (!format && fd->skip < bp->b_bcount - bp->b_resid) {
2020 if (!format && fd->skip < bp->bio_bcount - bp->bio_resid) {
2022 /* set up next transfer */
2023 fdc->state = DOSEEK;
2024 } else {
2025 /* ALL DONE */
2026 fd->skip = 0;
2027 fdc->bp = NULL;
2028 device_unbusy(fd->dev);
2021 /* set up next transfer */
2022 fdc->state = DOSEEK;
2023 } else {
2024 /* ALL DONE */
2025 fd->skip = 0;
2026 fdc->bp = NULL;
2027 device_unbusy(fd->dev);
2029 devstat_end_transaction_buf(&fd->device_stats, bp);
2028 devstat_end_transaction_bio(&fd->device_stats, bp);
2030 biodone(bp);
2031 fdc->fd = (fd_p) 0;
2032 fdc->fdu = -1;
2033 fdc->state = FINDWORK;
2034 }
2035 return (1);
2036 case RESETCTLR:
2037 fdc_reset(fdc);
2038 fdc->retry++;
2039 fdc->state = RESETCOMPLETE;
2040 return (0);
2041 case RESETCOMPLETE:
2042 /*
2043 * Discard all the results from the reset so that they
2044 * can't cause an unexpected interrupt later.
2045 */
2046 for (i = 0; i < 4; i++)
2047 (void)fd_sense_int(fdc, &st0, &cyl);
2048 fdc->state = STARTRECAL;
2049 /* Fall through. */
2050 case STARTRECAL:
2051 if(fd_cmd(fdc, 2, NE7CMD_RECAL, fdu, 0)) {
2052 /* arrgl */
2053 fdc->retry = 6;
2054 return (retrier(fdc));
2055 }
2056 fdc->state = RECALWAIT;
2057 return (0); /* will return later */
2058 case RECALWAIT:
2059 /* allow heads to settle */
2060 timeout(fd_pseudointr, fdc, hz / 8);
2061 fdc->state = RECALCOMPLETE;
2062 return (0); /* will return later */
2063 case RECALCOMPLETE:
2064 do {
2065 /*
2066 * See SEEKCOMPLETE for a comment on this:
2067 */
2068 if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
2069 return 0;
2070 if(fdc->fdct == FDC_NE765
2071 && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
2072 return 0; /* hope for a real intr */
2073 } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
2074 if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0)
2075 {
2076 if(fdc->retry > 3)
2077 /*
2078 * a recalibrate from beyond cylinder 77
2079 * will "fail" due to the FDC limitations;
2080 * since people used to complain much about
2081 * the failure message, try not logging
2082 * this one if it seems to be the first
2083 * time in a line
2084 */
2085 printf("fd%d: recal failed ST0 %b cyl %d\n",
2086 fdu, st0, NE7_ST0BITS, cyl);
2087 if(fdc->retry < 3) fdc->retry = 3;
2088 return (retrier(fdc));
2089 }
2090 fd->track = 0;
2091 /* Seek (probably) necessary */
2092 fdc->state = DOSEEK;
2093 return (1); /* will return immediatly */
2094 case MOTORWAIT:
2095 if(fd->flags & FD_MOTOR_WAIT)
2096 {
2097 return (0); /* time's not up yet */
2098 }
2099 if (fdc->flags & FDC_NEEDS_RESET) {
2100 fdc->state = RESETCTLR;
2101 fdc->flags &= ~FDC_NEEDS_RESET;
2102 } else {
2103 /*
2104 * If all motors were off, then the controller was
2105 * reset, so it has lost track of the current
2106 * cylinder. Recalibrate to handle this case.
2107 * But first, discard the results of the reset.
2108 */
2109 fdc->state = RESETCOMPLETE;
2110 }
2111 return (1); /* will return immediatly */
2112 default:
2113 device_printf(fdc->fdc_dev, "unexpected FD int->");
2114 if (fd_read_status(fdc, fd->fdsu) == 0)
2115 printf("FDC status :%x %x %x %x %x %x %x ",
2116 fdc->status[0],
2117 fdc->status[1],
2118 fdc->status[2],
2119 fdc->status[3],
2120 fdc->status[4],
2121 fdc->status[5],
2122 fdc->status[6] );
2123 else
2124 printf("No status available ");
2125 if (fd_sense_int(fdc, &st0, &cyl) != 0)
2126 {
2127 printf("[controller is dead now]\n");
2128 return (0);
2129 }
2130 printf("ST0 = %x, PCN = %x\n", st0, cyl);
2131 return (0);
2132 }
2133 /*XXX confusing: some branches return immediately, others end up here*/
2134 return (1); /* Come back immediatly to new state */
2135}
2136
2137static int
2138retrier(struct fdc_data *fdc)
2139{
2029 biodone(bp);
2030 fdc->fd = (fd_p) 0;
2031 fdc->fdu = -1;
2032 fdc->state = FINDWORK;
2033 }
2034 return (1);
2035 case RESETCTLR:
2036 fdc_reset(fdc);
2037 fdc->retry++;
2038 fdc->state = RESETCOMPLETE;
2039 return (0);
2040 case RESETCOMPLETE:
2041 /*
2042 * Discard all the results from the reset so that they
2043 * can't cause an unexpected interrupt later.
2044 */
2045 for (i = 0; i < 4; i++)
2046 (void)fd_sense_int(fdc, &st0, &cyl);
2047 fdc->state = STARTRECAL;
2048 /* Fall through. */
2049 case STARTRECAL:
2050 if(fd_cmd(fdc, 2, NE7CMD_RECAL, fdu, 0)) {
2051 /* arrgl */
2052 fdc->retry = 6;
2053 return (retrier(fdc));
2054 }
2055 fdc->state = RECALWAIT;
2056 return (0); /* will return later */
2057 case RECALWAIT:
2058 /* allow heads to settle */
2059 timeout(fd_pseudointr, fdc, hz / 8);
2060 fdc->state = RECALCOMPLETE;
2061 return (0); /* will return later */
2062 case RECALCOMPLETE:
2063 do {
2064 /*
2065 * See SEEKCOMPLETE for a comment on this:
2066 */
2067 if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
2068 return 0;
2069 if(fdc->fdct == FDC_NE765
2070 && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
2071 return 0; /* hope for a real intr */
2072 } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
2073 if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0)
2074 {
2075 if(fdc->retry > 3)
2076 /*
2077 * a recalibrate from beyond cylinder 77
2078 * will "fail" due to the FDC limitations;
2079 * since people used to complain much about
2080 * the failure message, try not logging
2081 * this one if it seems to be the first
2082 * time in a line
2083 */
2084 printf("fd%d: recal failed ST0 %b cyl %d\n",
2085 fdu, st0, NE7_ST0BITS, cyl);
2086 if(fdc->retry < 3) fdc->retry = 3;
2087 return (retrier(fdc));
2088 }
2089 fd->track = 0;
2090 /* Seek (probably) necessary */
2091 fdc->state = DOSEEK;
2092 return (1); /* will return immediatly */
2093 case MOTORWAIT:
2094 if(fd->flags & FD_MOTOR_WAIT)
2095 {
2096 return (0); /* time's not up yet */
2097 }
2098 if (fdc->flags & FDC_NEEDS_RESET) {
2099 fdc->state = RESETCTLR;
2100 fdc->flags &= ~FDC_NEEDS_RESET;
2101 } else {
2102 /*
2103 * If all motors were off, then the controller was
2104 * reset, so it has lost track of the current
2105 * cylinder. Recalibrate to handle this case.
2106 * But first, discard the results of the reset.
2107 */
2108 fdc->state = RESETCOMPLETE;
2109 }
2110 return (1); /* will return immediatly */
2111 default:
2112 device_printf(fdc->fdc_dev, "unexpected FD int->");
2113 if (fd_read_status(fdc, fd->fdsu) == 0)
2114 printf("FDC status :%x %x %x %x %x %x %x ",
2115 fdc->status[0],
2116 fdc->status[1],
2117 fdc->status[2],
2118 fdc->status[3],
2119 fdc->status[4],
2120 fdc->status[5],
2121 fdc->status[6] );
2122 else
2123 printf("No status available ");
2124 if (fd_sense_int(fdc, &st0, &cyl) != 0)
2125 {
2126 printf("[controller is dead now]\n");
2127 return (0);
2128 }
2129 printf("ST0 = %x, PCN = %x\n", st0, cyl);
2130 return (0);
2131 }
2132 /*XXX confusing: some branches return immediately, others end up here*/
2133 return (1); /* Come back immediatly to new state */
2134}
2135
2136static int
2137retrier(struct fdc_data *fdc)
2138{
2140 register struct buf *bp;
2139 struct bio *bp;
2141 struct fd_data *fd;
2142 int fdu;
2143
2144 bp = fdc->bp;
2145
2146 /* XXX shouldn't this be cached somewhere? */
2140 struct fd_data *fd;
2141 int fdu;
2142
2143 bp = fdc->bp;
2144
2145 /* XXX shouldn't this be cached somewhere? */
2147 fdu = FDUNIT(minor(bp->b_dev));
2146 fdu = FDUNIT(minor(bp->bio_dev));
2148 fd = devclass_get_softc(fd_devclass, fdu);
2149 if (fd->options & FDOPT_NORETRY)
2150 goto fail;
2151
2152 switch (fdc->retry) {
2153 case 0: case 1: case 2:
2154 fdc->state = SEEKCOMPLETE;
2155 break;
2156 case 3: case 4: case 5:
2157 fdc->state = STARTRECAL;
2158 break;
2159 case 6:
2160 fdc->state = RESETCTLR;
2161 break;
2162 case 7:
2163 break;
2164 default:
2165 fail:
2166 {
2147 fd = devclass_get_softc(fd_devclass, fdu);
2148 if (fd->options & FDOPT_NORETRY)
2149 goto fail;
2150
2151 switch (fdc->retry) {
2152 case 0: case 1: case 2:
2153 fdc->state = SEEKCOMPLETE;
2154 break;
2155 case 3: case 4: case 5:
2156 fdc->state = STARTRECAL;
2157 break;
2158 case 6:
2159 fdc->state = RESETCTLR;
2160 break;
2161 case 7:
2162 break;
2163 default:
2164 fail:
2165 {
2167 dev_t sav_b_dev = bp->b_dev;
2166 dev_t sav_bio_dev = bp->bio_dev;
2168 /* Trick diskerr */
2167 /* Trick diskerr */
2169 bp->b_dev = makedev(major(bp->b_dev),
2170 (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART);
2168 bp->bio_dev = makedev(major(bp->bio_dev),
2169 (FDUNIT(minor(bp->bio_dev))<<3)|RAW_PART);
2171 diskerr(bp, "hard error", LOG_PRINTF,
2172 fdc->fd->skip / DEV_BSIZE,
2173 (struct disklabel *)NULL);
2170 diskerr(bp, "hard error", LOG_PRINTF,
2171 fdc->fd->skip / DEV_BSIZE,
2172 (struct disklabel *)NULL);
2174 bp->b_dev = sav_b_dev;
2173 bp->bio_dev = sav_bio_dev;
2175 if (fdc->flags & FDC_STAT_VALID)
2176 {
2177 printf(
2178 " (ST0 %b ST1 %b ST2 %b cyl %u hd %u sec %u)\n",
2179 fdc->status[0], NE7_ST0BITS,
2180 fdc->status[1], NE7_ST1BITS,
2181 fdc->status[2], NE7_ST2BITS,
2182 fdc->status[3], fdc->status[4],
2183 fdc->status[5]);
2184 }
2185 else
2186 printf(" (No status)\n");
2187 }
2174 if (fdc->flags & FDC_STAT_VALID)
2175 {
2176 printf(
2177 " (ST0 %b ST1 %b ST2 %b cyl %u hd %u sec %u)\n",
2178 fdc->status[0], NE7_ST0BITS,
2179 fdc->status[1], NE7_ST1BITS,
2180 fdc->status[2], NE7_ST2BITS,
2181 fdc->status[3], fdc->status[4],
2182 fdc->status[5]);
2183 }
2184 else
2185 printf(" (No status)\n");
2186 }
2188 bp->b_ioflags |= BIO_ERROR;
2189 bp->b_error = EIO;
2190 bp->b_resid += bp->b_bcount - fdc->fd->skip;
2187 bp->bio_flags |= BIO_ERROR;
2188 bp->bio_error = EIO;
2189 bp->bio_resid += bp->bio_bcount - fdc->fd->skip;
2191 fdc->bp = NULL;
2192 fdc->fd->skip = 0;
2193 device_unbusy(fd->dev);
2190 fdc->bp = NULL;
2191 fdc->fd->skip = 0;
2192 device_unbusy(fd->dev);
2194 devstat_end_transaction_buf(&fdc->fd->device_stats, bp);
2193 devstat_end_transaction_bio(&fdc->fd->device_stats, bp);
2195 biodone(bp);
2196 fdc->state = FINDWORK;
2197 fdc->flags |= FDC_NEEDS_RESET;
2198 fdc->fd = (fd_p) 0;
2199 fdc->fdu = -1;
2200 return (1);
2201 }
2202 fdc->retry++;
2203 return (1);
2204}
2205
2206static int
2207fdformat(dev, finfo, p)
2208 dev_t dev;
2209 struct fd_formb *finfo;
2210 struct proc *p;
2211{
2212 fdu_t fdu;
2213 fd_p fd;
2214
2215 struct buf *bp;
2216 int rv = 0, s;
2217 size_t fdblk;
2218
2219 fdu = FDUNIT(minor(dev));
2220 fd = devclass_get_softc(fd_devclass, fdu);
2221 fdblk = 128 << fd->ft->secsize;
2222
2223 /* set up a buffer header for fdstrategy() */
2224 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
2225 if(bp == 0)
2226 return ENOBUFS;
2227 /*
2228 * keep the process from being swapped
2229 */
2230 PHOLD(p);
2231 bzero((void *)bp, sizeof(struct buf));
2232 BUF_LOCKINIT(bp);
2233 BUF_LOCK(bp, LK_EXCLUSIVE);
2194 biodone(bp);
2195 fdc->state = FINDWORK;
2196 fdc->flags |= FDC_NEEDS_RESET;
2197 fdc->fd = (fd_p) 0;
2198 fdc->fdu = -1;
2199 return (1);
2200 }
2201 fdc->retry++;
2202 return (1);
2203}
2204
2205static int
2206fdformat(dev, finfo, p)
2207 dev_t dev;
2208 struct fd_formb *finfo;
2209 struct proc *p;
2210{
2211 fdu_t fdu;
2212 fd_p fd;
2213
2214 struct buf *bp;
2215 int rv = 0, s;
2216 size_t fdblk;
2217
2218 fdu = FDUNIT(minor(dev));
2219 fd = devclass_get_softc(fd_devclass, fdu);
2220 fdblk = 128 << fd->ft->secsize;
2221
2222 /* set up a buffer header for fdstrategy() */
2223 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
2224 if(bp == 0)
2225 return ENOBUFS;
2226 /*
2227 * keep the process from being swapped
2228 */
2229 PHOLD(p);
2230 bzero((void *)bp, sizeof(struct buf));
2231 BUF_LOCKINIT(bp);
2232 BUF_LOCK(bp, LK_EXCLUSIVE);
2234 bp->b_flags = B_PHYS | B_FORMAT;
2235 bp->b_iocmd = BIO_WRITE;
2233 bp->b_flags = B_PHYS;
2234 bp->b_iocmd = BIO_FORMAT;
2236
2237 /*
2238 * calculate a fake blkno, so fdstrategy() would initiate a
2239 * seek to the requested cylinder
2240 */
2241 bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
2242 + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE;
2243
2244 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
2245 bp->b_data = (caddr_t)finfo;
2246
2247 /* now do the format */
2248 bp->b_dev = dev;
2249 DEV_STRATEGY(bp, 0);
2250
2251 /* ...and wait for it to complete */
2252 s = splbio();
2253 while(!(bp->b_flags & B_DONE)) {
2254 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
2255 if (rv == EWOULDBLOCK)
2256 break;
2257 }
2258 splx(s);
2259
2260 if (rv == EWOULDBLOCK) {
2261 /* timed out */
2262 rv = EIO;
2263 device_unbusy(fd->dev);
2235
2236 /*
2237 * calculate a fake blkno, so fdstrategy() would initiate a
2238 * seek to the requested cylinder
2239 */
2240 bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
2241 + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE;
2242
2243 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
2244 bp->b_data = (caddr_t)finfo;
2245
2246 /* now do the format */
2247 bp->b_dev = dev;
2248 DEV_STRATEGY(bp, 0);
2249
2250 /* ...and wait for it to complete */
2251 s = splbio();
2252 while(!(bp->b_flags & B_DONE)) {
2253 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
2254 if (rv == EWOULDBLOCK)
2255 break;
2256 }
2257 splx(s);
2258
2259 if (rv == EWOULDBLOCK) {
2260 /* timed out */
2261 rv = EIO;
2262 device_unbusy(fd->dev);
2264 biodone(bp);
2263 biodone(&bp->b_io); /* XXX: HUH ? */
2265 }
2266 if (bp->b_ioflags & BIO_ERROR)
2267 rv = bp->b_error;
2268 /*
2269 * allow the process to be swapped
2270 */
2271 PRELE(p);
2272 BUF_UNLOCK(bp);
2273 BUF_LOCKFREE(bp);
2274 free(bp, M_TEMP);
2275 return rv;
2276}
2277
2278/*
2279 * TODO: don't allocate buffer on stack.
2280 */
2281
2282static int
2283fdioctl(dev, cmd, addr, flag, p)
2284 dev_t dev;
2285 u_long cmd;
2286 caddr_t addr;
2287 int flag;
2288 struct proc *p;
2289{
2290 fdu_t fdu = FDUNIT(minor(dev));
2291 fd_p fd = devclass_get_softc(fd_devclass, fdu);
2292 size_t fdblk;
2293
2294 struct fd_type *fdt;
2295 struct disklabel *dl;
2296 char buffer[DEV_BSIZE];
2297 int error = 0;
2298
2299 fdblk = 128 << fd->ft->secsize;
2300
2301 switch (cmd) {
2302 case DIOCGDINFO:
2303 bzero(buffer, sizeof (buffer));
2304 dl = (struct disklabel *)buffer;
2305 dl->d_secsize = fdblk;
2306 fdt = fd->ft;
2307 dl->d_secpercyl = fdt->size / fdt->tracks;
2308 dl->d_type = DTYPE_FLOPPY;
2309
2310 if (readdisklabel(dkmodpart(dev, RAW_PART), dl)
2311 == NULL)
2312 error = 0;
2313 else
2314 error = EINVAL;
2315
2316 *(struct disklabel *)addr = *dl;
2317 break;
2318
2319 case DIOCSDINFO:
2320 if ((flag & FWRITE) == 0)
2321 error = EBADF;
2322 break;
2323
2324 case DIOCWLABEL:
2325 if ((flag & FWRITE) == 0)
2326 error = EBADF;
2327 break;
2328
2329 case DIOCWDINFO:
2330 if ((flag & FWRITE) == 0) {
2331 error = EBADF;
2332 break;
2333 }
2334
2335 dl = (struct disklabel *)addr;
2336
2337 if ((error = setdisklabel((struct disklabel *)buffer, dl,
2338 (u_long)0)) != 0)
2339 break;
2340
2341 error = writedisklabel(dev, (struct disklabel *)buffer);
2342 break;
2343 case FD_FORM:
2344 if ((flag & FWRITE) == 0)
2345 error = EBADF; /* must be opened for writing */
2346 else if (((struct fd_formb *)addr)->format_version !=
2347 FD_FORMAT_VERSION)
2348 error = EINVAL; /* wrong version of formatting prog */
2349 else
2350 error = fdformat(dev, (struct fd_formb *)addr, p);
2351 break;
2352
2353 case FD_GTYPE: /* get drive type */
2354 *(struct fd_type *)addr = *fd->ft;
2355 break;
2356
2357 case FD_STYPE: /* set drive type */
2358 /* this is considered harmful; only allow for superuser */
2359 if (suser(p) != 0)
2360 return EPERM;
2361 *fd->ft = *(struct fd_type *)addr;
2362 break;
2363
2364 case FD_GOPTS: /* get drive options */
2365 *(int *)addr = fd->options;
2366 break;
2367
2368 case FD_SOPTS: /* set drive options */
2369 fd->options = *(int *)addr;
2370 break;
2371
2372 default:
2373 error = ENOTTY;
2374 break;
2375 }
2376 return (error);
2377}
2378
2379/*
2380 * Hello emacs, these are the
2381 * Local Variables:
2382 * c-indent-level: 8
2383 * c-continued-statement-offset: 8
2384 * c-continued-brace-offset: 0
2385 * c-brace-offset: -8
2386 * c-brace-imaginary-offset: 0
2387 * c-argdecl-indent: 8
2388 * c-label-offset: -8
2389 * c++-hanging-braces: 1
2390 * c++-access-specifier-offset: -8
2391 * c++-empty-arglist-indent: 8
2392 * c++-friend-offset: 0
2393 * End:
2394 */
2264 }
2265 if (bp->b_ioflags & BIO_ERROR)
2266 rv = bp->b_error;
2267 /*
2268 * allow the process to be swapped
2269 */
2270 PRELE(p);
2271 BUF_UNLOCK(bp);
2272 BUF_LOCKFREE(bp);
2273 free(bp, M_TEMP);
2274 return rv;
2275}
2276
2277/*
2278 * TODO: don't allocate buffer on stack.
2279 */
2280
2281static int
2282fdioctl(dev, cmd, addr, flag, p)
2283 dev_t dev;
2284 u_long cmd;
2285 caddr_t addr;
2286 int flag;
2287 struct proc *p;
2288{
2289 fdu_t fdu = FDUNIT(minor(dev));
2290 fd_p fd = devclass_get_softc(fd_devclass, fdu);
2291 size_t fdblk;
2292
2293 struct fd_type *fdt;
2294 struct disklabel *dl;
2295 char buffer[DEV_BSIZE];
2296 int error = 0;
2297
2298 fdblk = 128 << fd->ft->secsize;
2299
2300 switch (cmd) {
2301 case DIOCGDINFO:
2302 bzero(buffer, sizeof (buffer));
2303 dl = (struct disklabel *)buffer;
2304 dl->d_secsize = fdblk;
2305 fdt = fd->ft;
2306 dl->d_secpercyl = fdt->size / fdt->tracks;
2307 dl->d_type = DTYPE_FLOPPY;
2308
2309 if (readdisklabel(dkmodpart(dev, RAW_PART), dl)
2310 == NULL)
2311 error = 0;
2312 else
2313 error = EINVAL;
2314
2315 *(struct disklabel *)addr = *dl;
2316 break;
2317
2318 case DIOCSDINFO:
2319 if ((flag & FWRITE) == 0)
2320 error = EBADF;
2321 break;
2322
2323 case DIOCWLABEL:
2324 if ((flag & FWRITE) == 0)
2325 error = EBADF;
2326 break;
2327
2328 case DIOCWDINFO:
2329 if ((flag & FWRITE) == 0) {
2330 error = EBADF;
2331 break;
2332 }
2333
2334 dl = (struct disklabel *)addr;
2335
2336 if ((error = setdisklabel((struct disklabel *)buffer, dl,
2337 (u_long)0)) != 0)
2338 break;
2339
2340 error = writedisklabel(dev, (struct disklabel *)buffer);
2341 break;
2342 case FD_FORM:
2343 if ((flag & FWRITE) == 0)
2344 error = EBADF; /* must be opened for writing */
2345 else if (((struct fd_formb *)addr)->format_version !=
2346 FD_FORMAT_VERSION)
2347 error = EINVAL; /* wrong version of formatting prog */
2348 else
2349 error = fdformat(dev, (struct fd_formb *)addr, p);
2350 break;
2351
2352 case FD_GTYPE: /* get drive type */
2353 *(struct fd_type *)addr = *fd->ft;
2354 break;
2355
2356 case FD_STYPE: /* set drive type */
2357 /* this is considered harmful; only allow for superuser */
2358 if (suser(p) != 0)
2359 return EPERM;
2360 *fd->ft = *(struct fd_type *)addr;
2361 break;
2362
2363 case FD_GOPTS: /* get drive options */
2364 *(int *)addr = fd->options;
2365 break;
2366
2367 case FD_SOPTS: /* set drive options */
2368 fd->options = *(int *)addr;
2369 break;
2370
2371 default:
2372 error = ENOTTY;
2373 break;
2374 }
2375 return (error);
2376}
2377
2378/*
2379 * Hello emacs, these are the
2380 * Local Variables:
2381 * c-indent-level: 8
2382 * c-continued-statement-offset: 8
2383 * c-continued-brace-offset: 0
2384 * c-brace-offset: -8
2385 * c-brace-imaginary-offset: 0
2386 * c-argdecl-indent: 8
2387 * c-label-offset: -8
2388 * c++-hanging-braces: 1
2389 * c++-access-specifier-offset: -8
2390 * c++-empty-arglist-indent: 8
2391 * c++-friend-offset: 0
2392 * End:
2393 */