Rewritten floppy driver
[unix-history] / usr / src / sys.386bsd / i386 / isa / fd.c
CommitLineData
9f1c0bf9 1/*#define DEBUG 1*/
eac289cc
WJ
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 *
37 * @(#)fd.c 7.4 (Berkeley) 5/25/91
9f1c0bf9
JE
38 *
39 * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
40 * -------------------- ----- ----------------------
41 * CURRENT PATCH LEVEL: 1 00153
42 * -------------------- ----- ----------------------
43 *
44 * 20 Apr 93 Julian Elischer Heavily re worked, see notes below
45 *
46 * Largely rewritten to handle multiple controllers and drives
47 * By Julian Elischer, Sun Apr 4 16:34:33 WST 1993
48 */
49char rev[] = "$Revision: 1.10 $";
50/*
51 * $Header: /usr/src/sys.386bsd/i386/isa/RCS/fd.c,v 1.10 93/04/13 16:53:29 root Exp $
52 */
53/*
54 * $Log: fd.c,v $
55 * Revision 1.10 93/04/13 16:53:29 root
56 * make sure turning off a drive motor doesn't deselect another
57 * drive active at the time.
58 * Also added a pointer from the fd_data to it's fd_type.
59 *
60 * Revision 1.9 93/04/13 15:31:02 root
61 * make all seeks go through DOSEEK state so are sure of being done right.
62 *
63 * Revision 1.8 93/04/12 21:20:13 root
64 * only check if old fd is the one we are working on if there IS
65 * an old fd pointer. (in fdstate())
66 *
67 * Revision 1.7 93/04/11 17:05:35 root
68 * cleanup timeouts etc.
69 * also fix bug to select teh correct drive when running > 1 drive
70 * at a time.
71 *
72 * Revision 1.6 93/04/05 00:48:45 root
73 * change a timeout and add version to banner message
74 *
75 * Revision 1.5 93/04/04 16:39:08 root
76 * first working version.. some floppy controllers don't seem to
77 * like 2 int. status inquiries in a row.
78 *
eac289cc
WJ
79 */
80
81#include "fd.h"
82#if NFD > 0
83
84#include "param.h"
85#include "dkbad.h"
86#include "systm.h"
87#include "conf.h"
88#include "file.h"
89#include "ioctl.h"
90#include "buf.h"
91#include "uio.h"
9f1c0bf9 92#include "i386/isa/isa.h"
eac289cc
WJ
93#include "i386/isa/isa_device.h"
94#include "i386/isa/fdreg.h"
95#include "i386/isa/icu.h"
96#include "i386/isa/rtc.h"
97#undef NFD
98#define NFD 2
99
100#define FDUNIT(s) ((s>>3)&1)
101#define FDTYPE(s) ((s)&7)
102
103#define b_cylin b_resid
eac289cc
WJ
104#define FDBLK 512
105#define NUMTYPES 4
106
107struct fd_type {
108 int sectrac; /* sectors per track */
109 int secsize; /* size code for sectors */
110 int datalen; /* data len when secsize = 0 */
111 int gap; /* gap len between sectors */
112 int tracks; /* total num of tracks */
113 int size; /* size of disk in sectors */
114 int steptrac; /* steps per cylinder */
115 int trans; /* transfer speed code */
9f1c0bf9 116 int heads; /* number of heads */
eac289cc
WJ
117};
118
9f1c0bf9
JE
119struct fd_type fd_types[NUMTYPES] =
120{
121 { 18,2,0xFF,0x1B,80,2880,1,0,2 }, /* 1.44 meg HD 3.5in floppy */
122 { 15,2,0xFF,0x1B,80,2400,1,0,2 }, /* 1.2 meg HD floppy */
123 { 9,2,0xFF,0x23,40,720,2,1,2 }, /* 360k floppy in 1.2meg drive */
124 { 9,2,0xFF,0x2A,40,720,1,1,2 }, /* 360k floppy in DD drive */
eac289cc
WJ
125};
126
9f1c0bf9
JE
127#define DRVS_PER_CTLR 2
128/***********************************************************************\
129* Per controller structure. *
130\***********************************************************************/
131struct fdc_data
132{
133 int fdcu; /* our unit number */
134 int baseport;
135 int dmachan;
136 int flags;
137#define FDC_ATTACHED 0x01
138 struct fd_data *fd;
139 int fdu; /* the active drive */
eac289cc
WJ
140 struct buf head; /* Head of buf chain */
141 struct buf rhead; /* Raw head of buf chain */
9f1c0bf9
JE
142 int state;
143 int retry;
144 int status[7]; /* copy of the registers */
145}fdc_data[(NFD+1)/DRVS_PER_CTLR];
146
147/***********************************************************************\
148* Per drive structure. *
149* N per controller (presently 2) (DRVS_PER_CTLR) *
150\***********************************************************************/
151struct fd_data {
152 struct fdc_data *fdc;
153 int fdu; /* this unit number */
154 int fdsu; /* this units number on this controller */
155 int type; /* Drive type (HD, DD */
156 struct fd_type *ft; /* pointer to the type descriptor */
157 int flags;
158#define FD_OPEN 0x01 /* it's open */
159#define FD_ACTIVE 0x02 /* it's active */
160#define FD_MOTOR 0x04 /* motor should be on */
161#define FD_MOTOR_WAIT 0x08 /* motor coming up */
162 int skip;
163 int hddrv;
164 int track; /* where we think the head is */
165} fd_data[NFD];
166
167/***********************************************************************\
168* Throughout this file the following conventions will be used: *
169* fd is a pointer to the fd_data struct for the drive in question *
170* fdc is a pointer to the fdc_data struct for the controller *
171* fdu is the floppy drive unit number *
172* fdcu is the floppy controller unit number *
173* fdsu is the floppy drive unit number on that controller. (sub-unit) *
174\***********************************************************************/
175typedef int fdu_t;
176typedef int fdcu_t;
177typedef int fdsu_t;
178typedef struct fd_data *fd_p;
179typedef struct fdc_data *fdc_p;
180
181#define DEVIDLE 0
182#define FINDWORK 1
183#define DOSEEK 2
184#define SEEKCOMPLETE 3
185#define IOCOMPLETE 4
186#define RECALCOMPLETE 5
187#define STARTRECAL 6
188#define RESETCTLR 7
189#define SEEKWAIT 8
190#define RECALWAIT 9
191#define MOTORWAIT 10
192#define IOTIMEDOUT 11
193
194#ifdef DEBUG
195char *fdstates[] =
196{
197"DEVIDLE",
198"FINDWORK",
199"DOSEEK",
200"SEEKCOMPLETE",
201"IOCOMPLETE",
202"RECALCOMPLETE",
203"STARTRECAL",
204"RESETCTLR",
205"SEEKWAIT",
206"RECALWAIT",
207"MOTORWAIT",
208"IOTIMEDOUT"
209};
eac289cc
WJ
210
211
9f1c0bf9
JE
212int fd_debug = 1;
213#define TRACE0(arg) if(fd_debug) printf(arg)
214#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
215#else DEBUG
216#define TRACE0(arg)
217#define TRACE1(arg1,arg2)
218#endif DEBUG
eac289cc 219
9f1c0bf9 220extern int hz;
eac289cc 221/* state needed for current transfer */
eac289cc
WJ
222
223/****************************************************************************/
224/* autoconfiguration stuff */
225/****************************************************************************/
226int fdprobe(), fdattach(), fd_turnoff();
227
228struct isa_driver fddriver = {
229 fdprobe, fdattach, "fd",
230};
231
232/*
233 * probe for existance of controller
234 */
235fdprobe(dev)
236struct isa_device *dev;
237{
9f1c0bf9
JE
238 fdcu_t fdcu = dev->id_unit;
239 if(fdc_data[fdcu].flags & FDC_ATTACHED)
240 {
241 printf("fdc: same unit (%d) used multiple times\n",fdcu);
242 return 0;
243 }
244
245 fdc_data[fdcu].baseport = dev->id_iobase;
eac289cc
WJ
246
247 /* see if it can handle a command */
9f1c0bf9
JE
248 if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0)
249 {
eac289cc
WJ
250 return(0);
251 }
9f1c0bf9
JE
252 out_fdc(fdcu,0xDF);
253 out_fdc(fdcu,2);
254 return (IO_FDCSIZE);
eac289cc
WJ
255}
256
257/*
258 * wire controller into system, look for floppy units
259 */
260fdattach(dev)
261struct isa_device *dev;
262{
eac289cc 263 unsigned fdt,st0, cyl;
9f1c0bf9
JE
264 int hdr;
265 fdu_t fdu;
266 fdcu_t fdcu = dev->id_unit;
267 fdc_p fdc = fdc_data + fdcu;
268 fd_p fd;
269 int fdsu;
270
271 fdc->fdcu = fdcu;
272 fdc->flags |= FDC_ATTACHED;
273 fdc->dmachan = dev->id_drq;
274 fdc->state = DEVIDLE;
eac289cc
WJ
275
276 fdt = rtcin(RTC_FDISKETTE);
277 hdr = 0;
278
279 /* check for each floppy drive */
9f1c0bf9
JE
280 for (fdu = (fdcu * DRVS_PER_CTLR),fdsu = 0;
281 ((fdu < NFD) && (fdsu < DRVS_PER_CTLR));
282 fdu++,fdsu++)
283 {
eac289cc
WJ
284 /* is there a unit? */
285 if ((fdt & 0xf0) == RTCFDT_NONE)
286 continue;
287
288#ifdef notyet
289 /* select it */
9f1c0bf9
JE
290 fd_turnon1(fdu);
291 spinwait(1000); /* 1 sec */
292 out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
293 out_fdc(fdcu,fdsu);
294 spinwait(1000); /* 1 sec */
eac289cc
WJ
295
296 /* anything responding */
9f1c0bf9
JE
297 out_fdc(fdcu,NE7CMD_SENSEI);
298 st0 = in_fdc(fdcu);
299 cyl = in_fdc(fdcu);
eac289cc
WJ
300 if (st0 & 0xd0)
301 continue;
302
303#endif
9f1c0bf9
JE
304 fd_data[fdu].track = -2;
305 fd_data[fdu].fdc = fdc;
306 fd_data[fdu].fdsu = fdsu;
eac289cc
WJ
307 /* yes, announce it */
308 if (!hdr)
309 printf(" drives ");
310 else
311 printf(", ");
9f1c0bf9 312 printf("%d: ", fdu);
eac289cc 313
9f1c0bf9 314
eac289cc
WJ
315 if ((fdt & 0xf0) == RTCFDT_12M) {
316 printf("1.2M");
9f1c0bf9
JE
317 fd_data[fdu].type = 1;
318 fd_data[fdu].ft = fd_types + 1;
319
eac289cc
WJ
320 }
321 if ((fdt & 0xf0) == RTCFDT_144M) {
322 printf("1.44M");
9f1c0bf9
JE
323 fd_data[fdu].type = 0;
324 fd_data[fdu].ft = fd_types + 0;
eac289cc
WJ
325 }
326
327 fdt <<= 4;
9f1c0bf9 328 fd_turnoff(fdu);
eac289cc
WJ
329 hdr = 1;
330 }
331
9f1c0bf9 332 printf(" %s ",rev);
eac289cc 333 /* Set transfer to 500kbps */
9f1c0bf9 334 outb(fdc->baseport+fdctl,0); /*XXX*/
eac289cc
WJ
335}
336
337int
338fdsize(dev)
339dev_t dev;
340{
341 return(0);
342}
343
344/****************************************************************************/
345/* fdstrategy */
346/****************************************************************************/
347fdstrategy(bp)
348 register struct buf *bp; /* IO operation to perform */
349{
350 register struct buf *dp,*dp0,*dp1;
351 long nblocks,blknum;
9f1c0bf9
JE
352 int s;
353 fdcu_t fdcu;
354 fdu_t fdu;
355 fdc_p fdc;
356 fd_p fd;
357
358 fdu = FDUNIT(minor(bp->b_dev));
359 fd = &fd_data[fdu];
360 fdc = fd->fdc;
361 fdcu = fdc->fdcu;
eac289cc 362 /*type = FDTYPE(minor(bp->b_dev));*/
eac289cc 363
9f1c0bf9
JE
364 if ((fdu >= NFD) || (bp->b_blkno < 0)) {
365 printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
366 fdu, bp->b_blkno, bp->b_bcount);
eac289cc
WJ
367 pg("fd:error in fdstrategy");
368 bp->b_error = EINVAL;
369 bp->b_flags |= B_ERROR;
370 goto bad;
371 }
372 /*
373 * Set up block calculations.
374 */
375 blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
9f1c0bf9 376 nblocks = fd->ft->size;
eac289cc
WJ
377 if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
378 if (blknum == nblocks) {
379 bp->b_resid = bp->b_bcount;
380 } else {
381 bp->b_error = ENOSPC;
382 bp->b_flags |= B_ERROR;
383 }
384 goto bad;
385 }
9f1c0bf9
JE
386 bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
387 dp = &(fdc->head);
eac289cc
WJ
388 s = splbio();
389 disksort(dp, bp);
9f1c0bf9
JE
390 untimeout(fd_turnoff,fdu); /* a good idea */
391 fdstart(fdcu);
eac289cc
WJ
392 splx(s);
393 return;
394
395bad:
396 biodone(bp);
397}
398
399/****************************************************************************/
400/* motor control stuff */
9f1c0bf9 401/* remember to not deselect the drive we're working on */
eac289cc 402/****************************************************************************/
9f1c0bf9 403set_motor(fdcu_t fdcu, fdu_t fdu, int reset)
eac289cc
WJ
404{
405 int m0,m1;
9f1c0bf9
JE
406 int selunit;
407 fd_p fd;
408 if(fd = fdc_data[fdcu].fd)/* yes an assign! */
409 {
410 selunit = fd->fdsu;
411 }
412 else
413 {
414 selunit = 0;
415 }
416 m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR;
417 m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR;
418 outb(fdc_data[fdcu].baseport+fdout,
419 selunit
eac289cc
WJ
420 | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
421 | (m0 ? FDO_MOEN0 : 0)
422 | (m1 ? FDO_MOEN1 : 0));
9f1c0bf9
JE
423 TRACE1("[0x%x->fdout]",(
424 selunit
425 | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
426 | (m0 ? FDO_MOEN0 : 0)
427 | (m1 ? FDO_MOEN1 : 0)));
428}
429
430fd_turnoff(fdu_t fdu)
431{
432 fd_p fd = fd_data + fdu;
433 fd->flags &= ~FD_MOTOR;
434 set_motor(fd->fdc->fdcu,fd->fdsu,0);
435}
436
437fd_motor_on(fdu_t fdu)
438{
439 fd_p fd = fd_data + fdu;
440 fd->flags &= ~FD_MOTOR_WAIT;
441 if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
442 {
443 fd_pseudointr(fd->fdc->fdcu);
444 }
eac289cc
WJ
445}
446
9f1c0bf9 447fd_turnon(fdu_t fdu)
eac289cc 448{
9f1c0bf9
JE
449 fd_p fd = fd_data + fdu;
450 if(!(fd->flags & FD_MOTOR))
451 {
452 fd_turnon1(fdu);
453 fd->flags |= FD_MOTOR_WAIT;
454 timeout(fd_motor_on,fdu,hz); /* in 1 sec its ok */
455 }
eac289cc
WJ
456}
457
9f1c0bf9 458fd_turnon1(fdu_t fdu)
eac289cc 459{
9f1c0bf9
JE
460 fd_p fd = fd_data + fdu;
461 fd->flags |= FD_MOTOR;
462 set_motor(fd->fdc->fdcu,fd->fdsu,0);
eac289cc
WJ
463}
464
465/****************************************************************************/
466/* fdc in/out */
467/****************************************************************************/
468int
9f1c0bf9 469in_fdc(fdcu_t fdcu)
eac289cc 470{
9f1c0bf9 471 int baseport = fdc_data[fdcu].baseport;
eac289cc 472 int i, j = 100000;
9f1c0bf9
JE
473 while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM))
474 != (NE7_DIO|NE7_RQM) && j-- > 0)
eac289cc
WJ
475 if (i == NE7_RQM) return -1;
476 if (j <= 0)
477 return(-1);
9f1c0bf9
JE
478#ifdef DEBUG
479 i = inb(baseport+fddata);
480 TRACE1("[fddata->0x%x]",(unsigned char)i);
481 return(i);
482#else
483 return inb(baseport+fddata);
484#endif
eac289cc
WJ
485}
486
9f1c0bf9 487out_fdc(fdcu_t fdcu,int x)
eac289cc 488{
9f1c0bf9 489 int baseport = fdc_data[fdcu].baseport;
eac289cc
WJ
490 int i = 100000;
491
9f1c0bf9
JE
492 while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0);
493 while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0);
eac289cc 494 if (i <= 0) return (-1);
9f1c0bf9
JE
495 outb(baseport+fddata,x);
496 TRACE1("[0x%x->fddata]",x);
eac289cc
WJ
497 return (0);
498}
499
500static fdopenf;
501/****************************************************************************/
502/* fdopen/fdclose */
503/****************************************************************************/
504Fdopen(dev, flags)
505 dev_t dev;
506 int flags;
507{
9f1c0bf9 508 fdu_t fdu = FDUNIT(minor(dev));
eac289cc
WJ
509 /*int type = FDTYPE(minor(dev));*/
510 int s;
511
eac289cc 512 /* check bounds */
9f1c0bf9 513 if (fdu >= NFD) return(ENXIO);
eac289cc 514 /*if (type >= NUMTYPES) return(ENXIO);*/
9f1c0bf9 515 fd_data[fdu].flags |= FD_OPEN;
eac289cc 516
eac289cc
WJ
517 return 0;
518}
519
520fdclose(dev, flags)
521 dev_t dev;
522{
9f1c0bf9
JE
523 fdu_t fdu = FDUNIT(minor(dev));
524 fd_data[fdu].flags &= ~FD_OPEN;
eac289cc
WJ
525 return(0);
526}
527
528
9f1c0bf9
JE
529/***************************************************************\
530* fdstart *
531* We have just queued something.. if the controller is not busy *
532* then simulate the case where it has just finished a command *
533* So that it (the interrupt routine) looks on the queue for more*
534* work to do and picks up what we just added. *
535* If the controller is already busy, we need do nothing, as it *
536* will pick up our work when the present work completes *
537\***************************************************************/
538fdstart(fdcu_t fdcu)
eac289cc
WJ
539{
540 register struct buf *dp,*bp;
541 int s;
9f1c0bf9 542 fdu_t fdu;
eac289cc 543
eac289cc 544 s = splbio();
9f1c0bf9
JE
545 if(fdc_data[fdcu].state == DEVIDLE)
546 {
547 fdintr(fdcu);
eac289cc
WJ
548 }
549 splx(s);
550}
551
9f1c0bf9 552fd_timeout(fdcu_t fdcu)
eac289cc 553{
9f1c0bf9 554 fdu_t fdu = fdc_data[fdcu].fdu;
eac289cc
WJ
555 int st0, st3, cyl;
556 struct buf *dp,*bp;
557
9f1c0bf9 558 dp = &fdc_data[fdcu].head;
eac289cc
WJ
559 bp = dp->b_actf;
560
9f1c0bf9
JE
561 out_fdc(fdcu,NE7CMD_SENSED);
562 out_fdc(fdcu,fd_data[fdu].hddrv);
563 st3 = in_fdc(fdcu);
564
565 out_fdc(fdcu,NE7CMD_SENSEI);
566 st0 = in_fdc(fdcu);
567 cyl = in_fdc(fdcu);
568 printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
569 fdu,
570 st0,
571 NE7_ST0BITS,
572 cyl,
573 st3,
574 NE7_ST3BITS);
575
576 if (bp)
577 {
578 retrier(fdcu);
579 fdc_data[fdcu].status[0] = 0xc0;
580 fdc_data[fdcu].state = IOTIMEDOUT;
581 if( fdc_data[fdcu].retry < 6)
582 fdc_data[fdcu].retry = 6;
583 }
584 else
585 {
586 fdc_data[fdcu].fd = (fd_p) 0;
587 fdc_data[fdcu].fdu = -1;
588 fdc_data[fdcu].state = DEVIDLE;
589 }
590 fd_pseudointr(fdcu);
591}
eac289cc 592
9f1c0bf9
JE
593/* just ensure it has the right spl */
594fd_pseudointr(fdcu_t fdcu)
595{
596 int s;
597 s = splbio();
598 fdintr(fdcu);
599 splx(s);
600}
eac289cc 601
9f1c0bf9
JE
602/***********************************************************************\
603* fdintr *
604* keep calling the state machine until it returns a 0 *
605* ALWAYS called at SPLBIO *
606\***********************************************************************/
607fdintr(fdcu_t fdcu)
608{
609 fdc_p fdc = fdc_data + fdcu;
610 while(fdstate(fdcu, fdc));
eac289cc
WJ
611}
612
9f1c0bf9
JE
613/***********************************************************************\
614* The controller state machine. *
615* if it returns a non zero value, it should be called again immediatly *
616\***********************************************************************/
617int fdstate(fdcu_t fdcu, fdc_p fdc)
eac289cc 618{
eac289cc
WJ
619 int read,head,trac,sec,i,s,sectrac,cyl,st0;
620 unsigned long blknum;
9f1c0bf9
JE
621 fdu_t fdu = fdc->fdu;
622 fd_p fd;
623 register struct buf *dp,*bp;
eac289cc 624
9f1c0bf9 625 dp = &(fdc->head);
eac289cc 626 bp = dp->b_actf;
9f1c0bf9
JE
627 if(!bp)
628 {
629 /***********************************************\
630 * nothing left for this controller to do *
631 * Force into the IDLE state, *
632 \***********************************************/
633 fdc->state = DEVIDLE;
634 if(fdc->fd)
635 {
636 printf("unexpected valid fd pointer (fdu = %d)\n"
637 ,fdc->fdu);
638 fdc->fd = (fd_p) 0;
639 fdc->fdu = -1;
640 }
641 TRACE1("[fdc%d IDLE]",fdcu);
642 return(0);
643 }
644 fdu = FDUNIT(minor(bp->b_dev));
645 fd = fd_data + fdu;
646 if (fdc->fd && (fd != fdc->fd))
647 {
648 printf("confused fd pointers\n");
649 }
eac289cc 650 read = bp->b_flags & B_READ;
9f1c0bf9
JE
651 TRACE1("fd%d",fdu);
652 TRACE1("[%s]",fdstates[fdc->state]);
653 TRACE1("(0x%x)",fd->flags);
654 untimeout(fd_turnoff, fdu);
655 timeout(fd_turnoff,fdu,4 * hz);
656 switch (fdc->state)
657 {
658 case DEVIDLE:
659 case FINDWORK: /* we have found new work */
660 fdc->retry = 0;
661 fd->skip = 0;
662 fdc->fd = fd;
663 fdc->fdu = fdu;
664 /*******************************************************\
665 * If the next drive has a motor startup pending, then *
666 * it will start up in it's own good time *
667 \*******************************************************/
668 if(fd->flags & FD_MOTOR_WAIT)
669 {
670 fdc->state = MOTORWAIT;
671 return(0); /* come back later */
672 }
673 /*******************************************************\
674 * Maybe if it's not starting, it SHOULD be starting *
675 \*******************************************************/
676 if (!(fd->flags & FD_MOTOR))
677 {
678 fdc->state = MOTORWAIT;
679 fd_turnon(fdu);
680 return(0);
681 }
682 else /* at least make sure we are selected */
683 {
684 set_motor(fdcu,fd->fdsu,0);
685 }
686 fdc->state = DOSEEK;
687 break;
688 case DOSEEK:
689 if (bp->b_cylin == fd->track)
690 {
691 fdc->state = SEEKCOMPLETE;
692 break;
693 }
694 out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */
695 out_fdc(fdcu,fd->fdsu); /* Drive number */
696 out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac);
697 fd->track = -2;
698 fdc->state = SEEKWAIT;
699 return(0); /* will return later */
700 case SEEKWAIT:
701 /* allow heads to settle */
702 timeout(fd_pseudointr,fdcu,hz/50);
703 fdc->state = SEEKCOMPLETE;
704 return(0); /* will return later */
705 break;
706
707 case SEEKCOMPLETE : /* SEEK DONE, START DMA */
eac289cc 708 /* Make sure seek really happened*/
9f1c0bf9
JE
709 if(fd->track == -2)
710 {
711 int descyl = bp->b_cylin * fd->ft->steptrac;
712 out_fdc(fdcu,NE7CMD_SENSEI);
713 i = in_fdc(fdcu);
714 cyl = in_fdc(fdcu);
715 if (cyl != descyl)
716 {
717 printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", fdu,
718 descyl, cyl, i, NE7_ST0BITS);
719 return(retrier(fdcu));
eac289cc
WJ
720 }
721 }
722
9f1c0bf9
JE
723 fd->track = bp->b_cylin;
724 isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
725 FDBLK, fdc->dmachan);
eac289cc 726 blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
9f1c0bf9
JE
727 + fd->skip/FDBLK;
728 sectrac = fd->ft->sectrac;
729 sec = blknum % (sectrac * fd->ft->heads);
eac289cc
WJ
730 head = sec / sectrac;
731 sec = sec % sectrac + 1;
9f1c0bf9
JE
732/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu;
733
734 if (read)
735 {
736 out_fdc(fdcu,NE7CMD_READ); /* READ */
eac289cc 737 }
9f1c0bf9
JE
738 else
739 {
740 out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */
741 }
742 out_fdc(fdcu,head << 2 | fdu); /* head & unit */
743 out_fdc(fdcu,fd->track); /* track */
744 out_fdc(fdcu,head);
745 out_fdc(fdcu,sec); /* sector XXX +1? */
746 out_fdc(fdcu,fd->ft->secsize); /* sector size */
747 out_fdc(fdcu,sectrac); /* sectors/track */
748 out_fdc(fdcu,fd->ft->gap); /* gap size */
749 out_fdc(fdcu,fd->ft->datalen); /* data length */
750 fdc->state = IOCOMPLETE;
751 timeout(fd_timeout,fdcu,2 * hz);
752 return(0); /* will return later */
753 case IOCOMPLETE: /* IO DONE, post-analyze */
754 untimeout(fd_timeout,fdcu);
755 for(i=0;i<7;i++)
756 {
757 fdc->status[i] = in_fdc(fdcu);
758 }
759 case IOTIMEDOUT: /*XXX*/
760 isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
761 FDBLK, fdc->dmachan);
762 if (fdc->status[0]&0xF8)
763 {
764 return(retrier(fdcu));
eac289cc
WJ
765 }
766 /* All OK */
9f1c0bf9
JE
767 fd->skip += FDBLK;
768 if (fd->skip < bp->b_bcount)
769 {
770 /* set up next transfer */
771 blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
772 + fd->skip/FDBLK;
773 bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads));
774 fdc->state = DOSEEK;
775 }
776 else
777 {
eac289cc 778 /* ALL DONE */
9f1c0bf9 779 fd->skip = 0;
eac289cc
WJ
780 bp->b_resid = 0;
781 dp->b_actf = bp->av_forw;
782 biodone(bp);
9f1c0bf9
JE
783 fdc->fd = (fd_p) 0;
784 fdc->fdu = -1;
785 fdc->state = FINDWORK;
eac289cc 786 }
9f1c0bf9
JE
787 return(1);
788 case RESETCTLR:
eac289cc 789 /* Try a reset, keep motor on */
9f1c0bf9 790 set_motor(fdcu,fd->fdsu,1);
eac289cc 791 DELAY(100);
9f1c0bf9
JE
792 set_motor(fdcu,fd->fdsu,0);
793 outb(fdc->baseport+fdctl,fd->ft->trans);
794 TRACE1("[0x%x->fdctl]",fd->ft->trans);
795 fdc->retry++;
796 fdc->state = STARTRECAL;
eac289cc 797 break;
9f1c0bf9
JE
798 case STARTRECAL:
799 out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */
800 out_fdc(fdcu,0xDF);
801 out_fdc(fdcu,2);
802 out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
803 out_fdc(fdcu,fdu);
804 fdc->state = RECALWAIT;
805 return(0); /* will return later */
806 case RECALWAIT:
eac289cc 807 /* allow heads to settle */
9f1c0bf9
JE
808 timeout(fd_pseudointr,fdcu,hz/30);
809 fdc->state = RECALCOMPLETE;
810 return(0); /* will return later */
811 case RECALCOMPLETE:
812 out_fdc(fdcu,NE7CMD_SENSEI);
813 st0 = in_fdc(fdcu);
814 cyl = in_fdc(fdcu);
815 if (cyl != 0)
816 {
817 printf("fd%d: recal failed ST0 %b cyl %d\n", fdu,
818 st0, NE7_ST0BITS, cyl);
819 return(retrier(fdcu));
820 }
821 fd->track = 0;
822 /* Seek (probably) necessary */
823 fdc->state = DOSEEK;
824 return(1); /* will return immediatly */
825 case MOTORWAIT:
826 if(fd->flags & FD_MOTOR_WAIT)
827 {
828 return(0); /* time's not up yet */
829 }
830 fdc->state = DOSEEK;
831 return(1); /* will return immediatly */
eac289cc
WJ
832 default:
833 printf("Unexpected FD int->");
9f1c0bf9
JE
834 out_fdc(fdcu,NE7CMD_SENSEI);
835 st0 = in_fdc(fdcu);
836 cyl = in_fdc(fdcu);
eac289cc 837 printf("ST0 = %lx, PCN = %lx\n",i,sec);
9f1c0bf9
JE
838 out_fdc(fdcu,0x4A);
839 out_fdc(fdcu,fd->fdsu);
eac289cc 840 for(i=0;i<7;i++) {
9f1c0bf9 841 fdc->status[i] = in_fdc(fdcu);
eac289cc
WJ
842 }
843 printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
9f1c0bf9
JE
844 fdc->status[0],
845 fdc->status[1],
846 fdc->status[2],
847 fdc->status[3],
848 fdc->status[4],
849 fdc->status[5],
850 fdc->status[6] );
851 return(0);
eac289cc 852 }
9f1c0bf9
JE
853 return(1); /* Come back immediatly to new state */
854}
855
856retrier(fdcu_t fdcu)
857{
858 fdc_p fdc = fdc_data + fdcu;
859 register struct buf *dp,*bp;
860
861 dp = &(fdc->head);
862 bp = dp->b_actf;
863
864 switch(fdc->retry)
865 {
866 case 0: case 1: case 2:
867 fdc->state = SEEKCOMPLETE;
868 break;
869 case 3: case 4: case 5:
870 fdc->state = STARTRECAL;
eac289cc 871 break;
eac289cc 872 case 6:
9f1c0bf9
JE
873 fdc->state = RESETCTLR;
874 break;
eac289cc
WJ
875 case 7:
876 break;
877 default:
9f1c0bf9
JE
878 {
879 printf("fd%d: hard error (ST0 %b ",
880 fdc->fdu, fdc->status[0], NE7_ST0BITS);
881 printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
882 printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
883 printf(" ST3 %b ", fdc->status[3], NE7_ST3BITS);
884 printf("cyl %d hd %d sec %d)\n",
885 fdc->status[4], fdc->status[5], fdc->status[6]);
886 }
887 bp->b_flags |= B_ERROR;
888 bp->b_error = EIO;
889 bp->b_resid = bp->b_bcount - fdc->fd->skip;
890 dp->b_actf = bp->av_forw;
891 fdc->fd->skip = 0;
892 biodone(bp);
893 fdc->state = FINDWORK;
894 fdc->fd = (fd_p) 0;
895 fdc->fdu = -1;
896 return(1);
eac289cc 897 }
9f1c0bf9
JE
898 fdc->retry++;
899 return(1);
eac289cc
WJ
900}
901
eac289cc 902#endif
9f1c0bf9 903