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