Commit | Line | Data |
---|---|---|
01395141 C |
1 | /* flp.c 4.5 81/03/08 */ |
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 |