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;
40 /* descriptor flags */
111 q = malloc(sizeof(*q) + sizeof(void*)*size);
113 PGROUND(sizeof(Vdesc)*size +
115 sizeof(u16int)*size +
117 PGROUND(sizeof(Vring) +
121 if(p == nil || q == nil){
122 print("virtio: no memory for Vqueue\n");
129 p += sizeof(Vdesc)*size;
132 q->availent = (void*)p;
133 p += sizeof(u16int)*size;
134 q->availevent = (void*)p;
137 p = (uchar*)PGROUND((ulong)p);
140 q->usedent = (void*)p;
141 p += sizeof(Vused)*size;
142 q->usedevent = (void*)p;
145 q->nfree = q->size = size;
146 for(i=0; i<size; i++){
147 q->desc[i].next = q->free;
162 for(p = nil; p = pcimatch(p, 0, 0);){
165 if((p->did < 0x1000) || (p->did >= 0x1040))
169 if(pcicfgr16(p, 0x2E) != typ)
171 if((vd = malloc(sizeof(*vd))) == nil){
172 print("virtio: no memory for Vdev\n");
175 vd->port = p->mem[0].bar & ~0x1;
176 if(ioalloc(vd->port, p->mem[0].size, 0, "virtio") < 0){
177 print("virtio: port %lux in use\n", vd->port);
185 outb(vd->port+Status, 0);
187 vd->feat = inl(vd->port+Devfeat);
188 outb(vd->port+Status, Acknowledge|Driver);
189 for(i=0; i<nelem(vd->queue); i++){
190 outs(vd->port+Qselect, i);
191 n = ins(vd->port+Qsize);
192 if(n == 0 || (n & (n-1)) != 0)
194 if((vd->queue[i] = mkvqueue(n)) == nil)
197 outl(vd->port+Qaddr, PADDR(vd->queue[i]->desc)/BY2PG);
217 viointerrupt(Ureg *, void *arg)
226 if(inb(vd->port+Isr) & 1){
231 while((q->lastused ^ q->used->idx) & m){
232 id = q->usedent[q->lastused++ & m].id;
236 r->done = 1; /* hands off */
242 id = q->desc[free].next;
243 q->desc[free].next = q->free;
246 } while(q->desc[free].flags & Next);
255 return ((struct Rock*)arg)->done;
259 vioreq(Vdev *vd, int typ, void *a, long count, long secsize, uvlong lba)
279 rock.sleep = &up->sleep;
287 tsleep(&up->sleep, return0, 0, 500);
293 head = free = q->free;
295 d = &q->desc[free]; free = d->next;
296 d->addr = PADDR(&req);
297 d->len = sizeof(req);
300 d = &q->desc[free]; free = d->next;
302 d->len = secsize*count;
303 d->flags = typ ? Next : (Write|Next);
305 d = &q->desc[free]; free = d->next;
306 d->addr = PADDR(&status);
307 d->len = sizeof(status);
313 q->rock[head] = &rock;
316 q->availent[q->avail->idx++ & (q->size-1)] = head;
318 outs(vd->port+Qnotify, 0);
324 tsleep(rock.sleep, viodone, &rock, 1000);
328 viointerrupt(nil, vd);
335 viobio(SDunit *u, int, int write, void *a, long count, uvlong lba)
337 long ss, cc, max, ret;
346 if((cc = count) > max)
348 if(vioreq(vd, write != 0, (uchar*)a + ret, cc, ss, lba) != 0)
366 if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
367 if(vioreq(u->dev->ctlr, 4, nil, 0, 0, 0) != 0)
368 return sdsetsense(r, SDcheck, 3, 0xc, 2);
369 return sdsetsense(r, SDok, 0, 0, 0);
371 if((i = sdfakescsi(r)) != SDnostatus)
372 return r->status = i;
373 if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
375 r->rlen = viobio(u, r->lun, rw == SDwrite, r->data, count, lba);
376 return r->status = SDok;
386 cap = inl(vd->port+Devspec+4);
388 cap |= inl(vd->port+Devspec);
389 if(u->sectors != cap){
414 for(vd = viopnpdevs(2); vd; vd = vd->next){
418 intrenable(vd->pci->intl, viointerrupt, vd, vd->pci->tbdf, "virtio");
419 outb(vd->port+Status, inb(vd->port+Status) | DriverOk);
421 if((s = malloc(sizeof(*s))) == nil)
425 s->ifc = &sdvirtioifc;
437 SDifc sdvirtioifc = {
445 vioverify, /* verify */
446 vioonline, /* online */