xref: /original-bsd/sys/vax/vax/flp.c (revision 6c57d260)
1 /*	flp.c	4.5	81/03/09	*/
2 
3 #if VAX780
4 #include "../h/flp.h"
5 #include "../h/param.h"
6 #include "../h/systm.h"
7 #include "../h/conf.h"
8 #include "../h/dir.h"
9 #include "../h/user.h"
10 #include "../h/mtpr.h"
11 #include "../h/buf.h"
12 #include "../h/cons.h"
13 #include "../h/cpu.h"
14 
15 struct {
16 	short	fl_state;		/* open and busy flags */
17 	short	fl_active;		/* driver state flag */
18 	struct	buf *fl_buf;		/* buffer we're using */
19 	unsigned char *fl_xaddr;	/* transfer address */
20 	short	fl_errcnt;
21 } fltab;
22 
23 /*ARGSUSED*/
24 flopen(dev, flag)
25 	dev_t dev;
26 	int flag;
27 {
28 	struct buf *geteblk();
29 
30 #if VAX750
31 	if (cpu != VAX_780) {
32 		u.u_error = ENXIO;
33 		return;
34 	}
35 #endif
36 	if (fltab.fl_state != 0) {
37 		u.u_error = ENXIO;
38 		return;
39 	}
40 	fltab.fl_state = FL_OPEN;
41 	fltab.fl_buf = geteblk();
42 	fltab.fl_active = FL_IDLE;
43 }
44 
45 /*ARGSUSED*/
46 flclose(dev, flag)
47 	dev_t dev;
48 	int flag;
49 {
50 
51 	brelse(fltab.fl_buf);
52 	fltab.fl_state = 0;
53 }
54 
55 flstrategy(rw)
56 	int rw;
57 {
58 	register struct buf *bp;
59 	register unsigned i;
60 
61 	/*
62 	 * Assume one block read/written for each call -
63 	 * and enforce this by checking for block size of 128.
64 	 * Use the b_blkno field to address
65 	 * physical, 128-byte blocks (u.u_offset/128).
66 	 * This is checked for validity, and is further interpreted as:
67 	 *
68 	 *	track# * (sectors/track) + sector #
69 	 */
70 	if (u.u_count == 0)
71 		return;
72 	(void) spl4();
73 	while (fltab.fl_state & FL_BUSY)
74 		sleep((caddr_t)&fltab, PRIBIO);
75 	fltab.fl_state |= FL_BUSY;
76 	(void) spl0();
77 
78 	bp = fltab.fl_buf;
79 	while ((i = min(RXBYSEC, u.u_count)) != 0) {
80 		bp->b_blkno = u.u_offset>>7;
81 		if (bp->b_blkno >= MAXSEC || (u.u_offset & 0177) != 0) {
82 			/* block number out of range */
83 			/* or offset in middle of block */
84 			u.u_error = ENXIO;
85 			break;
86 		}
87 		if (rw == B_WRITE) {
88 			iomove(bp->b_un.b_addr, i, B_WRITE);
89 			if (u.u_error != 0)
90 				break;
91 		}
92 		bp->b_flags = rw;
93 		(void) spl4();
94 		flstart();
95 		while ((bp->b_flags & B_DONE) == 0)
96 			sleep((caddr_t)bp, PRIBIO);
97 		(void) spl0();
98 		if (bp->b_flags & B_ERROR) {
99 			u.u_error = EIO;
100 			break;
101 		}
102 		if (rw == B_READ) {
103 			iomove(bp->b_un.b_addr, i, B_READ);
104 			if (u.u_error != 0)
105 				break;
106 		}
107 	}
108 	u.u_count = bp->b_resid;
109 	fltab.fl_state &= ~FL_BUSY;
110 	wakeup((caddr_t)&fltab);
111 }
112 
113 /*ARGSUSED*/
114 flread(dev)
115 	dev_t dev;
116 {
117 
118 	flstrategy(B_READ);
119 }
120 
121 /*ARGSUSED*/
122 flwrite(dev)
123 	dev_t dev;
124 {
125 
126 	flstrategy(B_WRITE);
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