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