xref: /original-bsd/sys/vax/vax/flp.c (revision a4d3ae46)
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.1 (Berkeley) 06/05/86
7  */
8 
9 #if VAX780
10 #include "param.h"
11 #include "systm.h"
12 #include "conf.h"
13 #include "dir.h"
14 #include "user.h"
15 #include "buf.h"
16 #include "uio.h"
17 
18 #include "cons.h"
19 #include "cpu.h"
20 #include "flp.h"
21 #include "mtpr.h"
22 
23 struct {
24 	short	fl_state;		/* open and busy flags */
25 	short	fl_active;		/* driver state flag */
26 	struct	buf *fl_buf;		/* buffer we're using */
27 	unsigned char *fl_xaddr;	/* transfer address */
28 	short	fl_errcnt;
29 } fltab;
30 
31 /*ARGSUSED*/
32 flopen(dev, flag)
33 	dev_t dev;
34 	int flag;
35 {
36 	struct buf *geteblk();
37 
38 	if (cpu != VAX_780)
39 		return (ENXIO);
40 	if (fltab.fl_state != 0)
41 		return (ENXIO);
42 	fltab.fl_state = FL_OPEN;
43 	fltab.fl_buf = geteblk(512);
44 	fltab.fl_active = FL_IDLE;
45 	return (0);
46 }
47 
48 /*ARGSUSED*/
49 flclose(dev, flag)
50 	dev_t dev;
51 	int flag;
52 {
53 
54 	brelse(fltab.fl_buf);
55 	fltab.fl_state = 0;
56 }
57 
58 floperation(rw, uio)
59 	enum uio_rw rw;
60 	struct uio *uio;
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 (rw == UIO_WRITE) {
92 			error = uiomove(bp->b_un.b_addr, i, UIO_WRITE, uio);
93 			if (error)
94 				break;
95 		}
96 		bp->b_flags = 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 (rw == UIO_READ) {
107 			error = uiomove(bp->b_un.b_addr, i, UIO_READ, 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 /*ARGSUSED*/
118 flread(dev, uio)
119 	dev_t dev;
120 	struct uio *uio;
121 {
122 
123 	return (floperation(UIO_READ, uio));
124 }
125 
126 /*ARGSUSED*/
127 flwrite(dev, uio)
128 	dev_t dev;
129 	struct uio *uio;
130 {
131 
132 	return (floperation(UIO_WRITE, uio));
133 }
134 
135 flstart()
136 {
137 	register struct buf *bp;
138 
139 	bp = fltab.fl_buf;
140 	fltab.fl_active = FL_MAND;
141 	fltab.fl_errcnt = 0;
142 	fltab.fl_xaddr = (unsigned char *) bp->b_un.b_addr;
143 	bp->b_resid = 0;
144 	bp->b_bcount = RXBYSEC; /* always transfer a full sector */
145 
146 	if ((mfpr(TXCS) & TXCS_RDY) == 0)
147 		/* not ready to receive order */
148 		return;
149 	/*
150 	 * Wake up floppy LSI software with command
151 	 */
152 	fltab.fl_active = FL_SEC;
153 	if ((bp->b_flags&B_READ) == B_READ)
154 		mtpr(TXDB, FL_RS);
155 	else
156 		mtpr(TXDB, FL_WS);
157 }
158 
159 /*
160  * See if we want to transmit something
161  * to the floppy - and do it
162  */
163 conxfl()
164 {
165 	register int databyte;
166 	register struct buf *bp;
167 
168 	bp = fltab.fl_buf;
169 	switch (fltab.fl_active) {
170 
171 	case FL_MAND:		/* send command */
172 		if ((bp->b_flags&B_READ) == B_READ)
173 			mtpr(TXDB,FL_RS);
174 		else
175 			mtpr(TXDB,  FL_WS);
176 		fltab.fl_active = FL_SEC;
177 		break;
178 
179 	case FL_SEC:		/* send sector address */
180 		databyte = (int)bp->b_blkno % RXSTRK + 1;
181 		mtpr(TXDB, FL_DATA | databyte);
182 		fltab.fl_active = FL_TRACK;
183 		break;
184 
185 	case FL_TRACK:		/* send track address */
186 		databyte = (int)bp->b_blkno / RXSTRK;
187 		mtpr(TXDB , FL_DATA | databyte);
188 		if ((bp->b_flags&B_READ) == B_READ)
189 			/* prepare to receive complete */
190 			fltab.fl_active = FL_COM;
191 		else
192 			/* prepare to send data */
193 			fltab.fl_active = FL_DAX;
194 		break;
195 
196 	case FL_DAX:
197 		databyte = *(fltab.fl_xaddr++);
198 		mtpr(TXDB, FL_DATA | databyte);
199 		if (--bp->b_bcount == 0)
200 			fltab.fl_active = FL_COM;
201 		break;
202 
203 	case FL_CAN:		/* give cancel order */
204 		mtpr(TXDB, FL_CANCEL);
205 		if (++fltab.fl_errcnt <= FLERRS) {
206 			/* If error count permits, retry order */
207 			fltab.fl_active = FL_MAND;
208 			bp->b_bcount = RXBYSEC;
209 			fltab.fl_xaddr = (unsigned char *) bp->b_un.b_addr;
210 		} else {
211 			/*
212 			 * We're really stupid today - call it an
213 			 * error and give up
214 			 */
215 			bp->b_flags |= B_ERROR | B_DONE;
216 			bp->b_resid = -RXBYSEC;
217 			fltab.fl_active = FL_IDLE;
218 			wakeup((caddr_t)bp);
219 		}
220 	}
221 }
222 
223 cnrfl(c)
224 	int c;
225 {
226 	register int datum;
227 	register struct buf *bp;
228 
229 	datum = c;
230 	bp = fltab.fl_buf;
231 	if (datum == FL_PERR) {
232 		/*
233 		 * Got a protocol error - cancel the
234 		 * current function and try again if error count isn't
235 		 * too great.  First, though, make sure that an actual
236 		 * transaction is in progress (so a spurious error from
237 		 * the LSI won't screw us up too much!
238 		 */
239 		if (fltab.fl_active != FL_IDLE)
240 			fltab.fl_active = FL_CAN;
241 	} else switch(fltab.fl_active ) {
242 
243 	case FL_DAR:		/* expecting a datum */
244 		if ((c&RXDB_ID) != FL_DATA)
245 			goto error;
246 		*(fltab.fl_xaddr++) = (c & RXDB_DATA);
247 		if (--bp->b_bcount==0) {
248 			fltab.fl_active = FL_IDLE;
249 			bp->b_flags |= B_DONE;
250 			wakeup((caddr_t)bp);
251 		}
252 		break;
253 
254 	case FL_COM:		/* expecting a "function complete" */
255 		if ((c&RXDB_ID)!= FL_FFC || (c&FL_ERR) == FL_ERR){
256 error:
257 			bp->b_flags |= B_ERROR | B_DONE;
258 			bp->b_resid = -bp->b_bcount;
259 			fltab.fl_active = FL_IDLE;
260 			wakeup((caddr_t)bp);
261 		} else if ((bp->b_flags&B_READ) == B_READ)
262 			/* got function complete, now get data */
263 			fltab.fl_active = FL_DAR;
264 		else {
265 			/* got function complete on write - finish up */
266 			fltab.fl_active = FL_IDLE;
267 			bp->b_flags |= B_DONE;
268 				wakeup((caddr_t)bp);
269 		}
270 		break;
271 	}
272 }
273 #endif
274