2 #include "../port/lib.h"
8 #include "../port/error.h"
10 #include "../port/sd.h"
12 typedef struct Vring Vring;
13 typedef struct Vdesc Vdesc;
14 typedef struct Vused Vused;
15 typedef struct Vqueue Vqueue;
16 typedef struct Vdev Vdev;
108 q = malloc(sizeof(*q) + sizeof(void*)*size);
110 PGROUND(sizeof(Vdesc)*size +
112 sizeof(u16int)*size +
114 PGROUND(sizeof(Vring) +
118 if(p == nil || q == nil){
119 print("mkvqueue: no memory for Vqueue\n");
126 p += sizeof(Vdesc)*size;
129 q->availent = (void*)p;
130 p += sizeof(u16int)*size;
131 q->availevent = (void*)p;
134 p = (uchar*)PGROUND((ulong)p);
137 q->usedent = (void*)p;
138 p += sizeof(Vused)*size;
139 q->usedevent = (void*)p;
142 q->nfree = q->size = size;
143 for(i=0; i<size; i++){
144 q->desc[i].next = q->free;
154 Vdev *vd, *head, *tail;
160 for(p = nil; p = pcimatch(p, 0, 0);){
163 if((p->did < 0x1000) || (p->did >= 0x1040))
167 if(pcicfgr16(p, 0x2E) != typ)
169 if((vd = malloc(sizeof(*vd))) == nil){
170 print("viopnpdevs: cannot allocate memory for Vdev\n");
173 vd->port = p->mem[0].bar & ~0x1;
178 outb(vd->port+Status, 0);
180 vd->feat = inl(vd->port+Devfeat);
181 outb(vd->port+Status, Acknowledge|Driver);
182 for(i=0; i<nelem(vd->queue); i++){
183 outs(vd->port+Qselect, i);
184 if((n = ins(vd->port+Qsize)) == 0)
186 if((vd->queue[i] = mkvqueue(n)) == nil)
189 a = PADDR(vd->queue[i]->desc)/BY2PG;
190 outl(vd->port+Qaddr, a);
209 viointerrupt(Ureg *, void *arg)
217 if(inb(vd->port+Isr) & 1){
222 while((q->lastused ^ q->used->idx) & m){
223 id = q->usedent[q->lastused++ & m].id;
231 id = q->desc[free].next;
232 q->desc[free].next = q->free;
235 } while(q->desc[free].flags & Next);
244 return ((struct Rock*)arg)->done;
248 vioreq(Vdev *vd, int typ, void *a, long count, long secsize, uvlong lba)
268 rock.sleep = &up->sleep;
276 tsleep(&up->sleep, return0, 0, 500);
282 head = free = q->free;
284 d = &q->desc[free]; free = d->next;
285 d->addr = PADDR(&req);
286 d->len = sizeof(req);
289 d = &q->desc[free]; free = d->next;
291 d->len = secsize*count;
292 d->flags = typ ? Next : (Write|Next);
294 d = &q->desc[free]; free = d->next;
295 d->addr = PADDR(&status);
296 d->len = sizeof(status);
302 q->rock[head] = &rock;
305 q->availent[q->avail->idx++ & (q->size-1)] = head;
307 outs(vd->port+Qnotify, 0);
313 tsleep(rock.sleep, viodone, &rock, 1000);
317 viointerrupt(nil, vd);
324 viobio(SDunit *u, int, int write, void *a, long count, uvlong lba)
326 long ss, cc, max, ret;
335 if((cc = count) > max)
337 if(vioreq(vd, write != 0, (uchar*)a + ret, cc, ss, lba) != 0)
355 if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
356 if(vioreq(u->dev->ctlr, 4, nil, 0, 0, 0) != 0)
357 return sdsetsense(r, SDcheck, 3, 0xc, 2);
358 return sdsetsense(r, SDok, 0, 0, 0);
360 if((i = sdfakescsi(r)) != SDnostatus)
361 return r->status = i;
362 if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
364 r->rlen = viobio(u, r->lun, rw == SDwrite, r->data, count, lba);
365 return r->status = SDok;
375 cap = inl(vd->port+Devspec+4);
377 cap |= inl(vd->port+Devspec);
378 if(u->sectors != cap){
403 for(vd = viopnpdevs(2); vd; vd = vd->next){
407 intrenable(vd->pci->intl, viointerrupt, vd, vd->pci->tbdf, "sdvirtio");
408 outb(vd->port+Status, inb(vd->port+Status) | DriverOk);
410 s = malloc(sizeof(*s));
415 s->ifc = &sdvirtioifc;
427 SDifc sdvirtioifc = {
435 vioverify, /* verify */
436 vioonline, /* online */