xref: /original-bsd/sys/vax/vax/flp.c (revision 6884d44a)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)flp.c	7.4 (Berkeley) 12/16/90
7  */
8 
9 #if VAX780
10 #include "sys/param.h"
11 #include "sys/systm.h"
12 #include "sys/conf.h"
13 #include "sys/user.h"
14 #include "sys/buf.h"
15 
16 #include "cons.h"
17 #include "../include/cpu.h"
18 #include "flp.h"
19 #include "../include/mtpr.h"
20 
21 struct {
22 	short	fl_state;		/* open and busy flags */
23 	short	fl_active;		/* driver state flag */
24 	struct	buf *fl_buf;		/* buffer we're using */
25 	unsigned char *fl_xaddr;	/* transfer address */
26 	short	fl_errcnt;
27 } fltab;
28 
29 /*ARGSUSED*/
30 flopen(dev, flag)
31 	dev_t dev;
32 	int flag;
33 {
34 	struct buf *geteblk();
35 
36 	if (cpu != VAX_780)
37 		return (ENXIO);
38 	if (fltab.fl_state != 0)
39 		return (ENXIO);
40 	fltab.fl_state = FL_OPEN;
41 	fltab.fl_buf = geteblk(512);
42 	fltab.fl_active = FL_IDLE;
43 	return (0);
44 }
45 
46 /*ARGSUSED*/
47 flclose(dev, flag)
48 	dev_t dev;
49 	int flag;
50 {
51 
52 	brelse(fltab.fl_buf);
53 	fltab.fl_state = 0;
54 }
55 
56 /*ARGSUSED*/
57 flrw(dev, uio, flag)
58 	dev_t dev;
59 	struct uio *uio;
60 	int flag;
61 {
62 	register struct buf *bp;
63 	register int i;
64 	int error;
65 
66 	/*
67 	 * Assume one block read/written for each call -
68 	 * and enforce this by checking for block size of 128.
69 	 * Use the b_blkno field to address
70 	 * physical, 128-byte blocks (u.u_offset/128).
71 	 * This is checked for validity, and is further interpreted as:
72 	 *
73 	 *	track# * (sectors/track) + sector #
74 	 */
75 	if (uio->uio_resid == 0)
76 		return (0);
77 	(void) spl4();
78 	while (fltab.fl_state & FL_BUSY)
79 		sleep((caddr_t)&fltab, PRIBIO);
80 	fltab.fl_state |= FL_BUSY;
81 	(void) spl0();
82 
83 	bp = fltab.fl_buf;
84 	error = 0;
85 	while ((i = imin(RXBYSEC, uio->uio_resid)) > 0) {
86 		bp->b_blkno = uio->uio_offset>>7;
87 		if (bp->b_blkno >= MAXSEC || (uio->uio_offset & 0177) != 0) {
88 			error = ENXIO;
89 			break;
90 		}
91 		if (uio->uio_rw == UIO_WRITE) {
92 			error = uiomove(bp->b_un.b_addr, i, uio);
93 			if (error)
94 				break;
95 		}
96 		bp->b_flags = uio->uio_rw == UIO_WRITE ? B_WRITE : B_READ;
97 		(void) spl4();
98 		flstart();
99 		while ((bp->b_flags & B_DONE) == 0)
100 			sleep((caddr_t)bp, PRIBIO);
101 		(void) spl0();
102 		if (bp->b_flags & B_ERROR) {
103 			error = EIO;
104 			break;
105 		}
106 		if (uio->uio_rw == UIO_READ) {
107 			error = uiomove(bp->b_un.b_addr, i, uio);
108 			if (error)
109 				break;
110 		}
111 	}
112 	fltab.fl_state &= ~FL_BUSY;
113 	wakeup((caddr_t)&fltab);
114 	return (error);
115 }
116 
117 flstart()
118 {
119 	register struct buf *bp;
120 
121 	bp = fltab.fl_buf;
122 	fltab.fl_active = FL_MAND;
123 	fltab.fl_errcnt = 0;
124 	fltab.fl_xaddr = (unsigned char *) bp->b_un.b_addr;
125 	bp->b_resid = 0;
126 	bp->b_bcount = RXBYSEC; /* always transfer a full sector */
127 
128 	if ((mfpr(TXCS) & TXCS_RDY) == 0)
129 		/* not ready to receive order */
130 		return;
131 	/*
132 	 * Wake up floppy LSI software with command
133 	 */
134 	fltab.fl_active = FL_SEC;
135 	if ((bp->b_flags&B_READ) == B_READ)
136 		mtpr(TXDB, FL_RS);
137 	else
138 		mtpr(TXDB, FL_WS);
139 }
140 
141 /*
142  * See if we want to transmit something
143  * to the floppy - and do it
144  */
145 conxfl()
146 {
147 	register int databyte;
148 	register struct buf *bp;
149 
150 	bp = fltab.fl_buf;
151 	switch (fltab.fl_active) {
152 
153 	case FL_MAND:		/* send command */
154 		if ((bp->b_flags&B_READ) == B_READ)
155 			mtpr(TXDB,FL_RS);
156 		else
157 			mtpr(TXDB,  FL_WS);
158 		fltab.fl_active = FL_SEC;
159 		break;
160 
161 	case FL_SEC:		/* send sector address */
162 		databyte = (int)bp->b_blkno % RXSTRK + 1;
163 		mtpr(TXDB, FL_DATA | databyte);
164 		fltab.fl_active = FL_TRACK;
165 		break;
166 
167 	case FL_TRACK:		/* send track address */
168 		databyte = (int)bp->b_blkno / RXSTRK;
169 		mtpr(TXDB , FL_DATA | databyte);
170 		if ((bp->b_flags&B_READ) == B_READ)
171 			/* prepare to receive complete */
172 			fltab.fl_active = FL_COM;
173 		else
174 			/* prepare to send data */
175 			fltab.fl_active = FL_DAX;
176 		break;
177 
178 	case FL_DAX:
179 		databyte = *(fltab.fl_xaddr++);
180 		mtpr(TXDB, FL_DATA | databyte);
181 		if (--bp->b_bcount == 0)
182 			fltab.fl_active = FL_COM;
183 		break;
184 
185 	case FL_CAN:		/* give cancel order */
186 		mtpr(TXDB, FL_CANCEL);
187 		if (++fltab.fl_errcnt <= FLERRS) {
188 			/* If error count permits, retry order */
189 			fltab.fl_active = FL_MAND;
190 			bp->b_bcount = RXBYSEC;
191 			fltab.fl_xaddr = (unsigned char *) bp->b_un.b_addr;
192 		} else {
193 			/*
194 			 * We're really stupid today - call it an
195 			 * error and give up
196 			 */
197 			bp->b_flags |= B_ERROR | B_DONE;
198 			bp->b_resid = -RXBYSEC;
199 			fltab.fl_active = FL_IDLE;
200 			wakeup((caddr_t)bp);
201 		}
202 	}
203 }
204 
205 cnrfl(c)
206 	int c;
207 {
208 	register int datum;
209 	register struct buf *bp;
210 
211 	datum = c;
212 	bp = fltab.fl_buf;
213 	if (datum == FL_PERR) {
214 		/*
215 		 * Got a protocol error - cancel the
216 		 * current function and try again if error count isn't
217 		 * too great.  First, though, make sure that an actual
218 		 * transaction is in progress (so a spurious error from
219 		 * the LSI won't screw us up too much!
220 		 */
221 		if (fltab.fl_active != FL_IDLE)
222 			fltab.fl_active = FL_CAN;
223 	} else switch(fltab.fl_active ) {
224 
225 	case FL_DAR:		/* expecting a datum */
226 		if ((c&RXDB_ID) != FL_DATA)
227 			goto error;
228 		*(fltab.fl_xaddr++) = (c & RXDB_DATA);
229 		if (--bp->b_bcount==0) {
230 			fltab.fl_active = FL_IDLE;
231 			bp->b_flags |= B_DONE;
232 			wakeup((caddr_t)bp);
233 		}
234 		break;
235 
236 	case FL_COM:		/* expecting a "function complete" */
237 		if ((c&RXDB_ID)!= FL_FFC || (c&FL_ERR) == FL_ERR){
238 error:
239 			bp->b_flags |= B_ERROR | B_DONE;
240 			bp->b_resid = -bp->b_bcount;
241 			fltab.fl_active = FL_IDLE;
242 			wakeup((caddr_t)bp);
243 		} else if ((bp->b_flags&B_READ) == B_READ)
244 			/* got function complete, now get data */
245 			fltab.fl_active = FL_DAR;
246 		else {
247 			/* got function complete on write - finish up */
248 			fltab.fl_active = FL_IDLE;
249 			bp->b_flags |= B_DONE;
250 				wakeup((caddr_t)bp);
251 		}
252 		break;
253 	}
254 }
255 #endif
256