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