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* 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 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 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 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 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 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 252 qlmatch(QLock *q1, QLock *q2) 253 { 254 255 return q1 == q2; 256 } 257 258 int 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