1 #include "all.h"
2 #include "io.h"
3
4 enum { DEBUG = 0 };
5
6 extern long nhiob;
7 extern Hiob *hiob;
8
9 Iobuf*
getbuf(Device * d,Off addr,int flag)10 getbuf(Device *d, Off addr, int flag)
11 {
12 Iobuf *p, *s;
13 Hiob *hp;
14 Off h;
15
16 if(DEBUG)
17 print("getbuf %Z(%lld) f=%x\n", d, (Wideoff)addr, flag);
18 h = addr + (Off)(uintptr)d*1009;
19 if(h < 0)
20 h = ~h;
21 h %= nhiob;
22 hp = &hiob[h];
23
24 loop:
25 lock(hp);
26
27 /*
28 * look for it in the active list
29 */
30 s = hp->link;
31 for(p=s;;) {
32 if(p->addr == addr && p->dev == d) {
33 if(p != s) {
34 p->back->fore = p->fore;
35 p->fore->back = p->back;
36 p->fore = s;
37 p->back = s->back;
38 s->back = p;
39 p->back->fore = p;
40 hp->link = p;
41 }
42 unlock(hp);
43 qlock(p);
44 if(p->addr != addr || p->dev != d || iobufmap(p) == 0) {
45 qunlock(p);
46 goto loop;
47 }
48 p->flags |= flag;
49 return p;
50 }
51 p = p->fore;
52 if(p == s)
53 break;
54 }
55 if(flag & Bprobe) {
56 unlock(hp);
57 return 0;
58 }
59
60 /*
61 * not found
62 * take oldest unlocked entry in this queue
63 */
64 xloop:
65 p = s->back;
66 if(!canqlock(p)) {
67 if(p == hp->link) {
68 unlock(hp);
69 print("iobuf all locked\n");
70 goto loop;
71 }
72 s = p;
73 goto xloop;
74 }
75
76 /*
77 * its dangerous to flush the pseudo
78 * devices since they recursively call
79 * getbuf/putbuf. deadlock!
80 */
81 if(p->flags & Bres) {
82 qunlock(p);
83 if(p == hp->link) {
84 unlock(hp);
85 print("iobuf all reserved\n");
86 goto loop;
87 }
88 s = p;
89 goto xloop;
90 }
91 if(p->flags & Bmod) {
92 unlock(hp);
93 if(iobufmap(p)) {
94 if(!devwrite(p->dev, p->addr, p->iobuf))
95 p->flags &= ~(Bimm|Bmod);
96 iobufunmap(p);
97 }
98 qunlock(p);
99 goto loop;
100 }
101 hp->link = p;
102 p->addr = addr;
103 p->dev = d;
104 p->flags = flag;
105 // p->pc = getcallerpc(&d);
106 unlock(hp);
107 if(iobufmap(p))
108 if(flag & Brd) {
109 if(!devread(p->dev, p->addr, p->iobuf))
110 return p;
111 iobufunmap(p);
112 } else
113 return p;
114 else
115 print("iobuf cant map buffer\n");
116 p->flags = 0;
117 p->dev = devnone;
118 p->addr = -1;
119 qunlock(p);
120 return 0;
121 }
122
123 /*
124 * syncblock tries to put out a block per hashline
125 * returns 0 all done,
126 * returns 1 if it missed something
127 */
128 int
syncblock(void)129 syncblock(void)
130 {
131 Iobuf *p, *s, *q;
132 Hiob *hp;
133 long h;
134 int flag;
135
136 flag = 0;
137 for(h=0; h<nhiob; h++) {
138 q = 0;
139 hp = &hiob[h];
140 lock(hp);
141 s = hp->link;
142 for(p=s;;) {
143 if(p->flags & Bmod) {
144 if(q)
145 flag = 1; /* more than 1 mod/line */
146 q = p;
147 }
148 p = p->fore;
149 if(p == s)
150 break;
151 }
152 unlock(hp);
153 if(q) {
154 if(!canqlock(q)) {
155 flag = 1; /* missed -- was locked */
156 continue;
157 }
158 if(!(q->flags & Bmod)) {
159 qunlock(q);
160 continue;
161 }
162 if(iobufmap(q)) {
163 if(!devwrite(q->dev, q->addr, q->iobuf))
164 q->flags &= ~(Bmod|Bimm);
165 iobufunmap(q);
166 } else
167 flag = 1;
168 qunlock(q);
169 }
170 }
171 return flag;
172 }
173
174 void
sync(char * reason)175 sync(char *reason)
176 {
177 long i;
178
179 print("sync: %s\n", reason);
180 for(i=10*nhiob; i>0; i--)
181 if(!syncblock())
182 return;
183 print("sync shorted\n");
184 }
185
186 void
putbuf(Iobuf * p)187 putbuf(Iobuf *p)
188 {
189
190 if(canqlock(p))
191 print("buffer not locked %Z(%lld)\n", p->dev, (Wideoff)p->addr);
192 if(p->flags & Bimm) {
193 if(!(p->flags & Bmod))
194 print("imm and no mod %Z(%lld)\n",
195 p->dev, (Wideoff)p->addr);
196 if(!devwrite(p->dev, p->addr, p->iobuf))
197 p->flags &= ~(Bmod|Bimm);
198 }
199 iobufunmap(p);
200 qunlock(p);
201 }
202
203 int
checktag(Iobuf * p,int tag,Off qpath)204 checktag(Iobuf *p, int tag, Off qpath)
205 {
206 Tag *t;
207 static Off lastaddr;
208
209 t = (Tag*)(p->iobuf+BUFSIZE);
210 if(t->tag != tag) {
211 if(p->flags & Bmod) {
212 print("\ttag = %d/%llud; expected %lld/%d -- not flushed\n",
213 t->tag, (Wideoff)t->path, (Wideoff)qpath, tag);
214 return 2;
215 }
216 if(p->dev != nil && p->dev->type == Devcw)
217 cwfree(p->dev, p->addr);
218 if(p->addr != lastaddr)
219 print("\ttag = %G/%llud; expected %G/%lld -- flushed (%lld)\n",
220 t->tag, (Wideoff)t->path, tag, (Wideoff)qpath,
221 (Wideoff)p->addr);
222 lastaddr = p->addr;
223 p->dev = devnone;
224 p->addr = -1;
225 p->flags = 0;
226 return 2;
227 }
228 if(qpath != QPNONE) {
229 if((qpath ^ t->path) & ~QPDIR) {
230 if(1 || CHAT(0))
231 print("\ttag/path = %llud; expected %d/%llux\n",
232 (Wideoff)t->path, tag, (Wideoff)qpath);
233 return 0;
234 }
235 }
236 return 0;
237 }
238
239 void
settag(Iobuf * p,int tag,long qpath)240 settag(Iobuf *p, int tag, long qpath)
241 {
242 Tag *t;
243
244 t = (Tag*)(p->iobuf+BUFSIZE);
245 t->tag = tag;
246 if(qpath != QPNONE)
247 t->path = qpath & ~QPDIR;
248 p->flags |= Bmod;
249 }
250
251 int
qlmatch(QLock * q1,QLock * q2)252 qlmatch(QLock *q1, QLock *q2)
253 {
254
255 return q1 == q2;
256 }
257
258 int
iobufql(QLock * q)259 iobufql(QLock *q)
260 {
261 Iobuf *p, *s;
262 Hiob *hp;
263 Tag *t;
264 long h;
265 int tag;
266
267 for(h=0; h<nhiob; h++) {
268 hp = &hiob[h];
269 lock(hp);
270 s = hp->link;
271 for(p=s;;) {
272 if(qlmatch(q, p)) {
273 t = (Tag*)(p->iobuf+BUFSIZE);
274 tag = t->tag;
275 if(tag < 0 || tag >= MAXTAG)
276 tag = Tnone;
277 print("\tIobuf %Z(%lld) t=%s\n",
278 p->dev, (Wideoff)p->addr, tagnames[tag]);
279 unlock(hp);
280 return 1;
281 }
282 p = p->fore;
283 if(p == s)
284 break;
285 }
286 unlock(hp);
287 }
288 return 0;
289 }
290