Make the LINT kernel compile with -W -Wreturn-type -Wcomment -Werror, and
[unix-history] / sys / i386 / isa / fd.c
CommitLineData
15637ed4
RG
1/*#define DEBUG 1*/
2/*-
3 * Copyright (c) 1990 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Don Ahn.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
9b4b7d6e 37 * from: @(#)fd.c 7.4 (Berkeley) 5/25/91
4c45483e 38 * $Id: fd.c,v 1.6 1993/09/23 15:22:57 rgrimes Exp $
15637ed4 39 *
15637ed4
RG
40 */
41
42#include "fd.h"
43#if NFD > 0
44
45#include "param.h"
46#include "dkbad.h"
47#include "systm.h"
4c45483e 48#include "kernel.h"
15637ed4
RG
49#include "conf.h"
50#include "file.h"
51#include "ioctl.h"
293464ef 52#include "disklabel.h"
15637ed4
RG
53#include "buf.h"
54#include "uio.h"
70621ef2 55#include "syslog.h"
15637ed4
RG
56#include "i386/isa/isa.h"
57#include "i386/isa/isa_device.h"
58#include "i386/isa/fdreg.h"
59#include "i386/isa/icu.h"
60#include "i386/isa/rtc.h"
61#undef NFD
62#define NFD 2
63
64#define FDUNIT(s) ((s>>3)&1)
65#define FDTYPE(s) ((s)&7)
66
67#define b_cylin b_resid
68#define FDBLK 512
69#define NUMTYPES 4
70
71struct fd_type {
72 int sectrac; /* sectors per track */
73 int secsize; /* size code for sectors */
74 int datalen; /* data len when secsize = 0 */
75 int gap; /* gap len between sectors */
76 int tracks; /* total num of tracks */
77 int size; /* size of disk in sectors */
78 int steptrac; /* steps per cylinder */
79 int trans; /* transfer speed code */
80 int heads; /* number of heads */
81};
82
83struct fd_type fd_types[NUMTYPES] =
84{
85 { 18,2,0xFF,0x1B,80,2880,1,0,2 }, /* 1.44 meg HD 3.5in floppy */
86 { 15,2,0xFF,0x1B,80,2400,1,0,2 }, /* 1.2 meg HD floppy */
87 { 9,2,0xFF,0x23,40,720,2,1,2 }, /* 360k floppy in 1.2meg drive */
88 { 9,2,0xFF,0x2A,40,720,1,1,2 }, /* 360k floppy in DD drive */
89};
90
91#define DRVS_PER_CTLR 2
92/***********************************************************************\
93* Per controller structure. *
94\***********************************************************************/
95struct fdc_data
96{
97 int fdcu; /* our unit number */
98 int baseport;
99 int dmachan;
100 int flags;
101#define FDC_ATTACHED 0x01
102 struct fd_data *fd;
103 int fdu; /* the active drive */
104 struct buf head; /* Head of buf chain */
105 struct buf rhead; /* Raw head of buf chain */
106 int state;
107 int retry;
108 int status[7]; /* copy of the registers */
109}fdc_data[(NFD+1)/DRVS_PER_CTLR];
110
111/***********************************************************************\
112* Per drive structure. *
113* N per controller (presently 2) (DRVS_PER_CTLR) *
114\***********************************************************************/
115struct fd_data {
116 struct fdc_data *fdc;
117 int fdu; /* this unit number */
118 int fdsu; /* this units number on this controller */
119 int type; /* Drive type (HD, DD */
120 struct fd_type *ft; /* pointer to the type descriptor */
121 int flags;
122#define FD_OPEN 0x01 /* it's open */
123#define FD_ACTIVE 0x02 /* it's active */
124#define FD_MOTOR 0x04 /* motor should be on */
125#define FD_MOTOR_WAIT 0x08 /* motor coming up */
126 int skip;
127 int hddrv;
128 int track; /* where we think the head is */
129} fd_data[NFD];
130
131/***********************************************************************\
132* Throughout this file the following conventions will be used: *
133* fd is a pointer to the fd_data struct for the drive in question *
134* fdc is a pointer to the fdc_data struct for the controller *
135* fdu is the floppy drive unit number *
136* fdcu is the floppy controller unit number *
137* fdsu is the floppy drive unit number on that controller. (sub-unit) *
138\***********************************************************************/
139typedef int fdu_t;
140typedef int fdcu_t;
141typedef int fdsu_t;
142typedef struct fd_data *fd_p;
143typedef struct fdc_data *fdc_p;
144
145#define DEVIDLE 0
146#define FINDWORK 1
147#define DOSEEK 2
148#define SEEKCOMPLETE 3
149#define IOCOMPLETE 4
150#define RECALCOMPLETE 5
151#define STARTRECAL 6
152#define RESETCTLR 7
153#define SEEKWAIT 8
154#define RECALWAIT 9
155#define MOTORWAIT 10
156#define IOTIMEDOUT 11
157
158#ifdef DEBUG
159char *fdstates[] =
160{
161"DEVIDLE",
162"FINDWORK",
163"DOSEEK",
164"SEEKCOMPLETE",
165"IOCOMPLETE",
166"RECALCOMPLETE",
167"STARTRECAL",
168"RESETCTLR",
169"SEEKWAIT",
170"RECALWAIT",
171"MOTORWAIT",
172"IOTIMEDOUT"
173};
174
175
176int fd_debug = 1;
177#define TRACE0(arg) if(fd_debug) printf(arg)
178#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
4c45483e 179#else /* DEBUG */
15637ed4
RG
180#define TRACE0(arg)
181#define TRACE1(arg1,arg2)
4c45483e 182#endif /* DEBUG */
15637ed4 183
4c45483e
GW
184static void fdstart(fdcu_t);
185void fdintr(fdcu_t);
186static void fd_turnoff(caddr_t, int);
15637ed4
RG
187
188/****************************************************************************/
189/* autoconfiguration stuff */
190/****************************************************************************/
4c45483e
GW
191static int fdprobe(struct isa_device *);
192static int fdattach(struct isa_device *);
15637ed4
RG
193
194struct isa_driver fddriver = {
195 fdprobe, fdattach, "fd",
196};
197
198/*
199 * probe for existance of controller
200 */
4c45483e 201int
15637ed4 202fdprobe(dev)
4c45483e 203 struct isa_device *dev;
15637ed4
RG
204{
205 fdcu_t fdcu = dev->id_unit;
206 if(fdc_data[fdcu].flags & FDC_ATTACHED)
207 {
208 printf("fdc: same unit (%d) used multiple times\n",fdcu);
209 return 0;
210 }
211
212 fdc_data[fdcu].baseport = dev->id_iobase;
213
214 /* see if it can handle a command */
215 if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0)
216 {
217 return(0);
218 }
219 out_fdc(fdcu,0xDF);
220 out_fdc(fdcu,2);
221 return (IO_FDCSIZE);
222}
223
224/*
225 * wire controller into system, look for floppy units
226 */
4c45483e 227int
15637ed4 228fdattach(dev)
4c45483e 229 struct isa_device *dev;
15637ed4
RG
230{
231 unsigned fdt,st0, cyl;
232 int hdr;
233 fdu_t fdu;
234 fdcu_t fdcu = dev->id_unit;
235 fdc_p fdc = fdc_data + fdcu;
236 fd_p fd;
237 int fdsu;
238
239 fdc->fdcu = fdcu;
240 fdc->flags |= FDC_ATTACHED;
241 fdc->dmachan = dev->id_drq;
242 fdc->state = DEVIDLE;
243
244 fdt = rtcin(RTC_FDISKETTE);
245 hdr = 0;
246
247 /* check for each floppy drive */
248 for (fdu = (fdcu * DRVS_PER_CTLR),fdsu = 0;
249 ((fdu < NFD) && (fdsu < DRVS_PER_CTLR));
250 fdu++,fdsu++)
251 {
252 /* is there a unit? */
293464ef
JH
253 if ((fdt & 0xf0) == RTCFDT_NONE) {
254#define NO_TYPE NUMTYPES
255 fd_data[fdu].type = NO_TYPE;
15637ed4 256 continue;
293464ef 257 }
15637ed4
RG
258
259#ifdef notyet
260 /* select it */
261 fd_turnon1(fdu);
262 spinwait(1000); /* 1 sec */
263 out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
264 out_fdc(fdcu,fdsu);
265 spinwait(1000); /* 1 sec */
266
267 /* anything responding */
268 out_fdc(fdcu,NE7CMD_SENSEI);
269 st0 = in_fdc(fdcu);
270 cyl = in_fdc(fdcu);
271 if (st0 & 0xd0)
272 continue;
273
274#endif
275 fd_data[fdu].track = -2;
276 fd_data[fdu].fdc = fdc;
277 fd_data[fdu].fdsu = fdsu;
b7c9de13 278 printf("fd%d: unit %d type ", fdcu, fdu);
15637ed4
RG
279
280 if ((fdt & 0xf0) == RTCFDT_12M) {
b7c9de13 281 printf("1.2MB 5.25in\n");
15637ed4
RG
282 fd_data[fdu].type = 1;
283 fd_data[fdu].ft = fd_types + 1;
284
285 }
286 if ((fdt & 0xf0) == RTCFDT_144M) {
b7c9de13 287 printf("1.44MB 3.5in\n");
15637ed4
RG
288 fd_data[fdu].type = 0;
289 fd_data[fdu].ft = fd_types + 0;
290 }
291
292 fdt <<= 4;
4c45483e 293 fd_turnoff((caddr_t)fdu, 0);
15637ed4
RG
294 hdr = 1;
295 }
296
15637ed4
RG
297 /* Set transfer to 500kbps */
298 outb(fdc->baseport+fdctl,0); /*XXX*/
4c45483e 299 return 1;
15637ed4
RG
300}
301
302int
303fdsize(dev)
4c45483e 304 dev_t dev;
15637ed4
RG
305{
306 return(0);
307}
308
309/****************************************************************************/
310/* fdstrategy */
311/****************************************************************************/
4c45483e 312void fdstrategy(struct buf *bp)
15637ed4
RG
313{
314 register struct buf *dp,*dp0,*dp1;
315 long nblocks,blknum;
316 int s;
317 fdcu_t fdcu;
318 fdu_t fdu;
319 fdc_p fdc;
320 fd_p fd;
321
322 fdu = FDUNIT(minor(bp->b_dev));
323 fd = &fd_data[fdu];
324 fdc = fd->fdc;
325 fdcu = fdc->fdcu;
326 /*type = FDTYPE(minor(bp->b_dev));*/
327
328 if ((fdu >= NFD) || (bp->b_blkno < 0)) {
329 printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
330 fdu, bp->b_blkno, bp->b_bcount);
331 pg("fd:error in fdstrategy");
332 bp->b_error = EINVAL;
333 bp->b_flags |= B_ERROR;
334 goto bad;
335 }
336 /*
337 * Set up block calculations.
338 */
339 blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
340 nblocks = fd->ft->size;
341 if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
342 if (blknum == nblocks) {
343 bp->b_resid = bp->b_bcount;
344 } else {
345 bp->b_error = ENOSPC;
346 bp->b_flags |= B_ERROR;
347 }
348 goto bad;
349 }
350 bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
351 dp = &(fdc->head);
352 s = splbio();
353 disksort(dp, bp);
354 untimeout(fd_turnoff,fdu); /* a good idea */
355 fdstart(fdcu);
356 splx(s);
357 return;
358
359bad:
360 biodone(bp);
361}
362
363/****************************************************************************/
364/* motor control stuff */
365/* remember to not deselect the drive we're working on */
366/****************************************************************************/
4c45483e 367void
293464ef
JH
368set_motor(fdcu, fdu, reset)
369 fdcu_t fdcu;
370 fdu_t fdu;
371 int reset;
15637ed4
RG
372{
373 int m0,m1;
374 int selunit;
375 fd_p fd;
376 if(fd = fdc_data[fdcu].fd)/* yes an assign! */
377 {
378 selunit = fd->fdsu;
379 }
380 else
381 {
382 selunit = 0;
383 }
384 m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR;
385 m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR;
386 outb(fdc_data[fdcu].baseport+fdout,
387 selunit
388 | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
389 | (m0 ? FDO_MOEN0 : 0)
390 | (m1 ? FDO_MOEN1 : 0));
391 TRACE1("[0x%x->fdout]",(
392 selunit
393 | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
394 | (m0 ? FDO_MOEN0 : 0)
395 | (m1 ? FDO_MOEN1 : 0)));
396}
397
4c45483e
GW
398static void
399fd_turnoff(caddr_t arg1, int arg2)
15637ed4 400{
4c45483e 401 fdu_t fdu = (fdu_t)arg1;
293464ef
JH
402 int s;
403
15637ed4 404 fd_p fd = fd_data + fdu;
293464ef 405 s = splbio();
15637ed4
RG
406 fd->flags &= ~FD_MOTOR;
407 set_motor(fd->fdc->fdcu,fd->fdsu,0);
293464ef 408 splx(s);
15637ed4
RG
409}
410
4c45483e
GW
411void
412fd_motor_on(caddr_t arg1, int arg2)
15637ed4 413{
4c45483e 414 fdu_t fdu = (fdu_t)arg1;
293464ef
JH
415 int s;
416
15637ed4 417 fd_p fd = fd_data + fdu;
293464ef 418 s = splbio();
15637ed4
RG
419 fd->flags &= ~FD_MOTOR_WAIT;
420 if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
421 {
293464ef 422 fdintr(fd->fdc->fdcu);
15637ed4 423 }
293464ef 424 splx(s);
15637ed4
RG
425}
426
4c45483e
GW
427static void fd_turnon1(fdu_t);
428
429void
293464ef
JH
430fd_turnon(fdu)
431 fdu_t fdu;
15637ed4
RG
432{
433 fd_p fd = fd_data + fdu;
434 if(!(fd->flags & FD_MOTOR))
435 {
436 fd_turnon1(fdu);
437 fd->flags |= FD_MOTOR_WAIT;
4c45483e 438 timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */
15637ed4
RG
439 }
440}
441
4c45483e
GW
442static void
443fd_turnon1(fdu_t fdu)
15637ed4
RG
444{
445 fd_p fd = fd_data + fdu;
446 fd->flags |= FD_MOTOR;
447 set_motor(fd->fdc->fdcu,fd->fdsu,0);
448}
449
450/****************************************************************************/
451/* fdc in/out */
452/****************************************************************************/
453int
293464ef
JH
454in_fdc(fdcu)
455 fdcu_t fdcu;
15637ed4
RG
456{
457 int baseport = fdc_data[fdcu].baseport;
458 int i, j = 100000;
459 while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM))
460 != (NE7_DIO|NE7_RQM) && j-- > 0)
461 if (i == NE7_RQM) return -1;
462 if (j <= 0)
463 return(-1);
464#ifdef DEBUG
465 i = inb(baseport+fddata);
466 TRACE1("[fddata->0x%x]",(unsigned char)i);
467 return(i);
468#else
469 return inb(baseport+fddata);
470#endif
471}
472
4c45483e 473int
293464ef
JH
474out_fdc(fdcu, x)
475 fdcu_t fdcu;
476 int x;
15637ed4
RG
477{
478 int baseport = fdc_data[fdcu].baseport;
105c2acd 479 int i;
15637ed4 480
105c2acd
RG
481 /* Check that the direction bit is set */
482 i = 100000;
15637ed4 483 while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0);
105c2acd
RG
484 if (i <= 0) return (-1); /* Floppy timed out */
485
486 /* Check that the floppy controller is ready for a command */
487 i = 100000;
15637ed4 488 while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0);
105c2acd
RG
489 if (i <= 0) return (-1); /* Floppy timed out */
490
491 /* Send the command and return */
15637ed4
RG
492 outb(baseport+fddata,x);
493 TRACE1("[0x%x->fddata]",x);
494 return (0);
495}
496
15637ed4
RG
497/****************************************************************************/
498/* fdopen/fdclose */
499/****************************************************************************/
4c45483e 500int
15637ed4
RG
501Fdopen(dev, flags)
502 dev_t dev;
503 int flags;
504{
505 fdu_t fdu = FDUNIT(minor(dev));
506 /*int type = FDTYPE(minor(dev));*/
507 int s;
508
509 /* check bounds */
293464ef 510 if (fdu >= NFD || fd_data[fdu].type == NO_TYPE) return(ENXIO);
15637ed4
RG
511 /*if (type >= NUMTYPES) return(ENXIO);*/
512 fd_data[fdu].flags |= FD_OPEN;
513
514 return 0;
515}
516
4c45483e 517int
15637ed4
RG
518fdclose(dev, flags)
519 dev_t dev;
4c45483e 520 int flags;
15637ed4
RG
521{
522 fdu_t fdu = FDUNIT(minor(dev));
523 fd_data[fdu].flags &= ~FD_OPEN;
524 return(0);
525}
526
527
528/***************************************************************\
529* fdstart *
530* We have just queued something.. if the controller is not busy *
531* then simulate the case where it has just finished a command *
532* So that it (the interrupt routine) looks on the queue for more*
533* work to do and picks up what we just added. *
534* If the controller is already busy, we need do nothing, as it *
535* will pick up our work when the present work completes *
536\***************************************************************/
4c45483e 537static void
293464ef
JH
538fdstart(fdcu)
539 fdcu_t fdcu;
15637ed4
RG
540{
541 register struct buf *dp,*bp;
542 int s;
543 fdu_t fdu;
544
545 s = splbio();
546 if(fdc_data[fdcu].state == DEVIDLE)
547 {
548 fdintr(fdcu);
549 }
550 splx(s);
551}
552
4c45483e
GW
553static void
554fd_timeout(caddr_t arg1, int arg2)
15637ed4 555{
4c45483e 556 fdcu_t fdcu = (fdcu_t)arg1;
15637ed4
RG
557 fdu_t fdu = fdc_data[fdcu].fdu;
558 int st0, st3, cyl;
559 struct buf *dp,*bp;
293464ef 560 int s;
15637ed4
RG
561
562 dp = &fdc_data[fdcu].head;
293464ef 563 s = splbio();
15637ed4
RG
564 bp = dp->b_actf;
565
566 out_fdc(fdcu,NE7CMD_SENSED);
567 out_fdc(fdcu,fd_data[fdu].hddrv);
568 st3 = in_fdc(fdcu);
569
570 out_fdc(fdcu,NE7CMD_SENSEI);
571 st0 = in_fdc(fdcu);
572 cyl = in_fdc(fdcu);
573 printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
574 fdu,
575 st0,
576 NE7_ST0BITS,
577 cyl,
578 st3,
579 NE7_ST3BITS);
580
581 if (bp)
582 {
583 retrier(fdcu);
584 fdc_data[fdcu].status[0] = 0xc0;
585 fdc_data[fdcu].state = IOTIMEDOUT;
586 if( fdc_data[fdcu].retry < 6)
587 fdc_data[fdcu].retry = 6;
588 }
589 else
590 {
591 fdc_data[fdcu].fd = (fd_p) 0;
592 fdc_data[fdcu].fdu = -1;
593 fdc_data[fdcu].state = DEVIDLE;
594 }
293464ef
JH
595 fdintr(fdcu);
596 splx(s);
15637ed4
RG
597}
598
599/* just ensure it has the right spl */
4c45483e
GW
600static void
601fd_pseudointr(caddr_t arg1, int arg2)
15637ed4 602{
4c45483e 603 fdcu_t fdcu = (fdcu_t)arg1;
15637ed4
RG
604 int s;
605 s = splbio();
606 fdintr(fdcu);
607 splx(s);
608}
609
610/***********************************************************************\
611* fdintr *
612* keep calling the state machine until it returns a 0 *
613* ALWAYS called at SPLBIO *
614\***********************************************************************/
4c45483e
GW
615void
616fdintr(fdcu_t fdcu)
15637ed4
RG
617{
618 fdc_p fdc = fdc_data + fdcu;
4c45483e
GW
619 while(fdstate(fdcu, fdc))
620 ;
15637ed4
RG
621}
622
623/***********************************************************************\
624* The controller state machine. *
625* if it returns a non zero value, it should be called again immediatly *
626\***********************************************************************/
4c45483e
GW
627int
628fdstate(fdcu, fdc)
293464ef
JH
629 fdcu_t fdcu;
630 fdc_p fdc;
15637ed4 631{
4c45483e 632 int read, head, trac, sec = 0, i = 0, s, sectrac, cyl, st0;
15637ed4
RG
633 unsigned long blknum;
634 fdu_t fdu = fdc->fdu;
635 fd_p fd;
636 register struct buf *dp,*bp;
637
638 dp = &(fdc->head);
639 bp = dp->b_actf;
640 if(!bp)
641 {
642 /***********************************************\
643 * nothing left for this controller to do *
644 * Force into the IDLE state, *
645 \***********************************************/
646 fdc->state = DEVIDLE;
647 if(fdc->fd)
648 {
649 printf("unexpected valid fd pointer (fdu = %d)\n"
650 ,fdc->fdu);
651 fdc->fd = (fd_p) 0;
652 fdc->fdu = -1;
653 }
654 TRACE1("[fdc%d IDLE]",fdcu);
655 return(0);
656 }
657 fdu = FDUNIT(minor(bp->b_dev));
658 fd = fd_data + fdu;
659 if (fdc->fd && (fd != fdc->fd))
660 {
661 printf("confused fd pointers\n");
662 }
663 read = bp->b_flags & B_READ;
664 TRACE1("fd%d",fdu);
665 TRACE1("[%s]",fdstates[fdc->state]);
666 TRACE1("(0x%x)",fd->flags);
667 untimeout(fd_turnoff, fdu);
4c45483e 668 timeout(fd_turnoff, (caddr_t)fdu, 4 * hz);
15637ed4
RG
669 switch (fdc->state)
670 {
671 case DEVIDLE:
672 case FINDWORK: /* we have found new work */
673 fdc->retry = 0;
674 fd->skip = 0;
675 fdc->fd = fd;
676 fdc->fdu = fdu;
677 /*******************************************************\
678 * If the next drive has a motor startup pending, then *
679 * it will start up in it's own good time *
680 \*******************************************************/
681 if(fd->flags & FD_MOTOR_WAIT)
682 {
683 fdc->state = MOTORWAIT;
684 return(0); /* come back later */
685 }
686 /*******************************************************\
687 * Maybe if it's not starting, it SHOULD be starting *
688 \*******************************************************/
689 if (!(fd->flags & FD_MOTOR))
690 {
691 fdc->state = MOTORWAIT;
692 fd_turnon(fdu);
693 return(0);
694 }
695 else /* at least make sure we are selected */
696 {
697 set_motor(fdcu,fd->fdsu,0);
698 }
699 fdc->state = DOSEEK;
700 break;
701 case DOSEEK:
702 if (bp->b_cylin == fd->track)
703 {
704 fdc->state = SEEKCOMPLETE;
705 break;
706 }
707 out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */
708 out_fdc(fdcu,fd->fdsu); /* Drive number */
709 out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac);
710 fd->track = -2;
711 fdc->state = SEEKWAIT;
4c45483e 712 timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
15637ed4
RG
713 return(0); /* will return later */
714 case SEEKWAIT:
293464ef 715 untimeout(fd_timeout,fdcu);
15637ed4 716 /* allow heads to settle */
4c45483e 717 timeout(fd_pseudointr, (caddr_t)fdcu, hz / 50);
15637ed4
RG
718 fdc->state = SEEKCOMPLETE;
719 return(0); /* will return later */
720 break;
721
722 case SEEKCOMPLETE : /* SEEK DONE, START DMA */
723 /* Make sure seek really happened*/
724 if(fd->track == -2)
725 {
726 int descyl = bp->b_cylin * fd->ft->steptrac;
727 out_fdc(fdcu,NE7CMD_SENSEI);
728 i = in_fdc(fdcu);
729 cyl = in_fdc(fdcu);
730 if (cyl != descyl)
731 {
732 printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", fdu,
733 descyl, cyl, i, NE7_ST0BITS);
734 return(retrier(fdcu));
735 }
736 }
737
738 fd->track = bp->b_cylin;
739 isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
740 FDBLK, fdc->dmachan);
741 blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
742 + fd->skip/FDBLK;
743 sectrac = fd->ft->sectrac;
744 sec = blknum % (sectrac * fd->ft->heads);
745 head = sec / sectrac;
746 sec = sec % sectrac + 1;
747/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu;
748
749 if (read)
750 {
751 out_fdc(fdcu,NE7CMD_READ); /* READ */
752 }
753 else
754 {
755 out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */
756 }
757 out_fdc(fdcu,head << 2 | fdu); /* head & unit */
758 out_fdc(fdcu,fd->track); /* track */
759 out_fdc(fdcu,head);
760 out_fdc(fdcu,sec); /* sector XXX +1? */
761 out_fdc(fdcu,fd->ft->secsize); /* sector size */
762 out_fdc(fdcu,sectrac); /* sectors/track */
763 out_fdc(fdcu,fd->ft->gap); /* gap size */
764 out_fdc(fdcu,fd->ft->datalen); /* data length */
765 fdc->state = IOCOMPLETE;
4c45483e 766 timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
15637ed4
RG
767 return(0); /* will return later */
768 case IOCOMPLETE: /* IO DONE, post-analyze */
769 untimeout(fd_timeout,fdcu);
770 for(i=0;i<7;i++)
771 {
772 fdc->status[i] = in_fdc(fdcu);
773 }
774 case IOTIMEDOUT: /*XXX*/
775 isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
776 FDBLK, fdc->dmachan);
777 if (fdc->status[0]&0xF8)
778 {
779 return(retrier(fdcu));
780 }
781 /* All OK */
782 fd->skip += FDBLK;
783 if (fd->skip < bp->b_bcount)
784 {
785 /* set up next transfer */
786 blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
787 + fd->skip/FDBLK;
788 bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads));
789 fdc->state = DOSEEK;
790 }
791 else
792 {
793 /* ALL DONE */
794 fd->skip = 0;
795 bp->b_resid = 0;
796 dp->b_actf = bp->av_forw;
797 biodone(bp);
798 fdc->fd = (fd_p) 0;
799 fdc->fdu = -1;
800 fdc->state = FINDWORK;
801 }
802 return(1);
803 case RESETCTLR:
804 /* Try a reset, keep motor on */
805 set_motor(fdcu,fd->fdsu,1);
806 DELAY(100);
807 set_motor(fdcu,fd->fdsu,0);
808 outb(fdc->baseport+fdctl,fd->ft->trans);
809 TRACE1("[0x%x->fdctl]",fd->ft->trans);
810 fdc->retry++;
811 fdc->state = STARTRECAL;
812 break;
813 case STARTRECAL:
814 out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */
815 out_fdc(fdcu,0xDF);
816 out_fdc(fdcu,2);
817 out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
818 out_fdc(fdcu,fdu);
819 fdc->state = RECALWAIT;
820 return(0); /* will return later */
821 case RECALWAIT:
822 /* allow heads to settle */
4c45483e 823 timeout(fd_pseudointr, (caddr_t)fdcu, hz / 30);
15637ed4
RG
824 fdc->state = RECALCOMPLETE;
825 return(0); /* will return later */
826 case RECALCOMPLETE:
827 out_fdc(fdcu,NE7CMD_SENSEI);
828 st0 = in_fdc(fdcu);
829 cyl = in_fdc(fdcu);
830 if (cyl != 0)
831 {
832 printf("fd%d: recal failed ST0 %b cyl %d\n", fdu,
833 st0, NE7_ST0BITS, cyl);
834 return(retrier(fdcu));
835 }
836 fd->track = 0;
837 /* Seek (probably) necessary */
838 fdc->state = DOSEEK;
839 return(1); /* will return immediatly */
840 case MOTORWAIT:
841 if(fd->flags & FD_MOTOR_WAIT)
842 {
843 return(0); /* time's not up yet */
844 }
845 fdc->state = DOSEEK;
846 return(1); /* will return immediatly */
847 default:
848 printf("Unexpected FD int->");
849 out_fdc(fdcu,NE7CMD_SENSEI);
850 st0 = in_fdc(fdcu);
851 cyl = in_fdc(fdcu);
852 printf("ST0 = %lx, PCN = %lx\n",i,sec);
853 out_fdc(fdcu,0x4A);
854 out_fdc(fdcu,fd->fdsu);
855 for(i=0;i<7;i++) {
856 fdc->status[i] = in_fdc(fdcu);
857 }
858 printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
859 fdc->status[0],
860 fdc->status[1],
861 fdc->status[2],
862 fdc->status[3],
863 fdc->status[4],
864 fdc->status[5],
865 fdc->status[6] );
866 return(0);
867 }
868 return(1); /* Come back immediatly to new state */
869}
870
4c45483e 871int
293464ef
JH
872retrier(fdcu)
873 fdcu_t fdcu;
15637ed4
RG
874{
875 fdc_p fdc = fdc_data + fdcu;
876 register struct buf *dp,*bp;
877
878 dp = &(fdc->head);
879 bp = dp->b_actf;
880
881 switch(fdc->retry)
882 {
883 case 0: case 1: case 2:
884 fdc->state = SEEKCOMPLETE;
885 break;
886 case 3: case 4: case 5:
887 fdc->state = STARTRECAL;
888 break;
889 case 6:
890 fdc->state = RESETCTLR;
891 break;
892 case 7:
893 break;
894 default:
895 {
70621ef2
RG
896 diskerr(bp, "fd", "hard error", LOG_PRINTF,
897 fdc->fd->skip, (struct disklabel *)NULL);
898 printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS);
15637ed4
RG
899 printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
900 printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
15637ed4 901 printf("cyl %d hd %d sec %d)\n",
70621ef2 902 fdc->status[3], fdc->status[4], fdc->status[5]);
15637ed4
RG
903 }
904 bp->b_flags |= B_ERROR;
905 bp->b_error = EIO;
906 bp->b_resid = bp->b_bcount - fdc->fd->skip;
907 dp->b_actf = bp->av_forw;
908 fdc->fd->skip = 0;
909 biodone(bp);
70621ef2 910 fdc->state = FINDWORK;
15637ed4
RG
911 fdc->fd = (fd_p) 0;
912 fdc->fdu = -1;
293464ef 913 /* XXX abort current command, if any. */
70621ef2 914 return(1);
15637ed4
RG
915 }
916 fdc->retry++;
917 return(1);
918}
919
293464ef
JH
920/*
921 * fdioctl() from jc@irbs.UUCP (John Capo)
922 * i386/i386/conf.c needs to have fdioctl() declared and remove the line that
923 * defines fdioctl to be enxio.
924 *
925 * TODO: Reformat.
926 * Think about allocating buffer off stack.
927 * Don't pass uncast 0's and NULL's to read/write/setdisklabel().
928 * Watch out for NetBSD's different *disklabel() interface.
929 */
930
931int
932fdioctl (dev, cmd, addr, flag)
933dev_t dev;
934int cmd;
935caddr_t addr;
936int flag;
937{
938 struct fd_type *fdt;
939 struct disklabel *dl;
940 char buffer[DEV_BSIZE];
941 int error;
942
943 error = 0;
944
945 switch (cmd)
946 {
947 case DIOCGDINFO:
948 bzero(buffer, sizeof (buffer));
949 dl = (struct disklabel *)buffer;
950 dl->d_secsize = FDBLK;
70621ef2 951 fdt = fd_data[FDUNIT(minor(dev))].ft;
293464ef
JH
952 dl->d_secpercyl = fdt->size / fdt->tracks;
953 dl->d_type = DTYPE_FLOPPY;
954
955 if (readdisklabel(dev, fdstrategy, dl, NULL, 0, 0) == NULL)
956 error = 0;
957 else
958 error = EINVAL;
959
960 *(struct disklabel *)addr = *dl;
961 break;
962
963 case DIOCSDINFO:
964
965 if ((flag & FWRITE) == 0)
966 error = EBADF;
15637ed4 967
293464ef
JH
968 break;
969
970 case DIOCWLABEL:
971 if ((flag & FWRITE) == 0)
972 error = EBADF;
973
974 break;
975
976 case DIOCWDINFO:
977 if ((flag & FWRITE) == 0)
978 {
979 error = EBADF;
980 break;
981 }
982
983 dl = (struct disklabel *)addr;
984
985 if (error = setdisklabel ((struct disklabel *)buffer, dl, 0, NULL))
986 break;
987
988 error = writedisklabel(dev, fdstrategy, (struct disklabel *)buffer, NULL);
989 break;
990
991 default:
992 error = EINVAL;
993 break;
994 }
995 return (error);
996}
997
998#endif