2 #include "../port/lib.h"
7 #include "../port/pci.h"
9 #include "../port/error.h"
11 #include "../port/sd.h"
16 typedef struct Ctlr Ctlr;
63 u32int mps; /* mps = 1<<mpsshift */
75 /* controller registers */
96 qcmd(WS *ws, Ctlr *ctlr, int adm, u32int opc, u32int nsid, void *mptr, void *data, ulong len)
105 sq = &ctlr->sq[1+(m->machno % ctlr->nsq)];
106 if(conf.nmach > ctlr->nsq)
112 ws->sleep = &up->sleep;
114 ws->link = &sq->wait[sq->tail & sq->mask];
115 while(*ws->link != nil){
118 /* should be very rare */
124 e = &sq->base[((cid = sq->tail++) & sq->mask)<<4];
125 e[0] = opc | cid<<16;
141 if(len > ctlr->mps - (pa & ctlr->mps-1))
142 pa += ctlr->mps - (pa & ctlr->mps-1);
156 nvmeintr(Ureg *, void *arg)
158 u32int phaseshift, *e;
169 ctlr->reg[IntMs] = ctlr->ints;
170 for(cq = &ctlr->cq[nelem(ctlr->cq)-1]; cq >= ctlr->cq; cq--){
173 phaseshift = 16 - cq->shift;
175 e = &cq->base[(cq->head & cq->mask)<<2];
176 if(((e[3] ^ (cq->head << phaseshift)) & 0x10000) == 0)
179 if(0) iprint("nvmeintr: cq%d [%.4ux] %.8ux %.8ux %.8ux %.8ux\n",
180 (int)(cq - ctlr->cq), cq->head & cq->mask,
181 e[0], e[1], e[2], e[3]);
183 sq = &ctlr->sq[e[2] >> 16];
184 wp = &sq->wait[e[3] & sq->mask];
185 if((ws = *wp) != nil && ws->link == wp){
186 Rendez *z = ws->sleep;
188 ws->status = e[3]>>17;
192 ctlr->reg[DBell + ((cq-ctlr->cq)*2+1 << ctlr->dstrd)] = ++cq->head & cq->mask;
195 ctlr->reg[IntMc] = ctlr->ints;
196 iunlock(&ctlr->intr);
203 return *ws->link != ws;
210 Ctlr *ctlr = sq->ctlr;
213 ctlr->reg[DBell + ((sq-ctlr->sq)*2+0 << ctlr->dstrd)] = sq->tail & sq->mask;
215 assert(sq == &ctlr->sq[1+(m->machno % ctlr->nsq)]);
216 if(conf.nmach > ctlr->nsq)
223 tsleep(ws->sleep, wdone, ws, 5);
226 tsleep(ws->sleep, wdone, ws, 10);
233 checkstatus(u32int status, char *info)
237 snprint(up->genbuf, sizeof(up->genbuf), "%s: status %ux", info, status);
242 nvmebio(SDunit *u, int lun, int write, void *a, long count, uvlong lba)
244 u32int nsid, s, n, m, *e;
252 nsid = ctlr->nsid[u->subno];
256 m = (2*ctlr->mps - ((uintptr)p & ctlr->mps-1)) / s;
259 e = qcmd(&ws, ctlr, 0, write ? 0x01 : 0x02, nsid, nil, p, n*s);
263 e[13] = (count>n)<<6; /* sequential request */
266 checkstatus(wcmd(&ws), write ? "write" : "read");
271 return p - (uchar*)a;
282 if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91)
283 return sdsetsense(r, SDok, 0, 0, 0);
284 if((i = sdfakescsi(r)) != SDnostatus)
285 return r->status = i;
286 if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
288 r->rlen = nvmebio(u, r->lun, rw == SDwrite, r->data, count, lba);
289 return r->status = SDok;
293 nvmeverify(SDunit *u)
295 Ctlr *ctlr = u->dev->ctlr;
296 return u->subno < ctlr->nnsid;
300 nvmeonline(SDunit *u)
311 if((info = mallocalign(0x1000, ctlr->mps, 0, 0)) == nil)
314 e = qcmd(&ws, ctlr, 1, 0x06, ctlr->nsid[u->subno], nil, info, 0x1000);
315 e[10] = 0; // identify namespace
321 u->sectors = p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24
326 p = &info[128 + 4*(info[26]&15)];
327 lbaf = p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24;
328 u->secsize = 1<<((lbaf>>16)&0xFF);
331 memset(u->inquiry, 0, sizeof u->inquiry);
334 u->inquiry[4] = sizeof u->inquiry - 4;
335 memmove(u->inquiry+8, ctlr->ident+24, 20);
341 nvmerctl(SDunit *u, char *p, int l)
346 if((ctlr = u->dev->ctlr) == nil || ctlr->ident == nil)
352 p = seprint(p, e, "model\t%.20s\n", (char*)ctlr->ident+24);
353 p = seprint(p, e, "serial\t%.10s\n", (char*)ctlr->ident+4);
354 p = seprint(p, e, "firm\t%.6s\n", (char*)ctlr->ident+64);
355 p = seprint(p, e, "geometry %llud %lud\n", u->sectors, u->secsize);
361 cqalloc(Ctlr *ctlr, CQ *cq, u32int lgsize)
365 cq->shift = lgsize-4;
366 cq->mask = (1<<cq->shift)-1;
367 if((cq->base = mallocalign(1<<lgsize, ctlr->mps, 0, 0)) == nil)
369 memset(cq->base, 0, 1<<lgsize);
374 sqalloc(Ctlr *ctlr, SQ *sq, u32int lgsize)
378 sq->shift = lgsize-6;
379 sq->mask = (1<<sq->shift)-1;
380 if((sq->base = mallocalign(1<<lgsize, ctlr->mps, 0, 0)) == nil)
382 if((sq->wait = mallocz(sizeof(WS*)*(sq->mask+1), 1)) == nil)
384 memset(sq->base, 0, 1<<lgsize);
389 setupqueues(Ctlr *ctlr)
391 u32int lgsize, st, *e;
399 while(lgsize < 16+4 && lgsize < ctlr->mpsshift && 1<<lgsize < conf.nmach<<12-6+4)
402 /* CQID1: shared completion queue */
404 cqalloc(ctlr, cq, lgsize);
405 e = qcmd(&ws, ctlr, 1, 0x05, 0, nil, cq->base, 1<<lgsize);
406 e[10] = (cq - ctlr->cq) | cq->mask<<16;
407 e[11] = 3; /* IEN | PC */
408 checkstatus(wcmd(&ws), "create completion queue");
412 /* SQID[1..nmach]: submission queue per cpu */
413 for(i=1; i<=conf.nmach; i++){
415 sqalloc(ctlr, sq, 12);
416 e = qcmd(&ws, ctlr, 1, 0x01, 0, nil, sq->base, 0x1000);
417 e[10] = i | sq->mask<<16;
418 e[11] = (cq - ctlr->cq)<<16 | 1; /* CQID<<16 | PC */
424 memset(sq, 0, sizeof(*sq));
431 checkstatus(st, "create submission queues");
434 ctlr->ints |= 1<<(cq - ctlr->cq);
435 ctlr->reg[IntMc] = ctlr->ints;
436 iunlock(&ctlr->intr);
445 if(ctlr->ident == nil)
446 if((ctlr->ident = mallocalign(0x1000, ctlr->mps, 0, 0)) == nil)
448 if(ctlr->nsid == nil)
449 if((ctlr->nsid = mallocalign(0x1000, ctlr->mps, 0, 0)) == nil)
452 e = qcmd(&ws, ctlr, 1, 0x06, 0, nil, ctlr->ident, 0x1000);
453 e[10] = 1; // identify controller
454 checkstatus(wcmd(&ws), "identify controller");
456 e = qcmd(&ws, ctlr, 1, 0x06, 0, nil, ctlr->nsid, 0x1000);
457 e[10] = 2; // namespace list
459 ctlr->nsid[0] = 1; /* assume namespace #1 */
462 while(ctlr->nnsid < 1024 && ctlr->nsid[ctlr->nnsid] != 0)
467 nvmedisable(SDev *sd)
475 /* mask interrupts */
478 ctlr->reg[IntMs] = ~ctlr->ints;
479 iunlock(&ctlr->intr);
481 /* disable controller */
484 for(i = 0; i < 10; i++){
485 if((ctlr->reg[CSts] & 1) == 0)
487 tsleep(&up->sleep, return0, nil, 100);
490 snprint(name, sizeof(name), "%s (%s)", sd->name, sd->ifc->name);
491 intrdisable(ctlr->pci->intl, nvmeintr, ctlr, ctlr->pci->tbdf, name);
493 pciclrbme(ctlr->pci); /* dma disable */
495 for(i=0; i<nelem(ctlr->sq); i++){
496 free(ctlr->sq[i].base);
497 free(ctlr->sq[i].wait);
499 for(i=0; i<nelem(ctlr->cq); i++)
500 free(ctlr->cq[i].base);
502 memset(ctlr->sq, 0, sizeof(ctlr->sq));
503 memset(ctlr->cq, 0, sizeof(ctlr->cq));
524 snprint(name, sizeof(name), "%s (%s)", sd->name, sd->ifc->name);
525 intrenable(ctlr->pci->intl, nvmeintr, ctlr, ctlr->pci->tbdf, name);
528 print("%s: %s\n", name, up->errstr);
530 sd->nunit = 0; /* hack: prevent further probing */
534 pa = PCIWADDR(cqalloc(ctlr, &ctlr->cq[0], ctlr->mpsshift));
535 ctlr->reg[ACQBase0] = pa;
536 ctlr->reg[ACQBase1] = pa>>32;
538 pa = PCIWADDR(sqalloc(ctlr, &ctlr->sq[0], ctlr->mpsshift));
539 ctlr->reg[ASQBase0] = pa;
540 ctlr->reg[ASQBase1] = pa>>32;
542 ctlr->reg[AQAttr] = ctlr->sq[0].mask | ctlr->cq[0].mask<<16;
545 pcisetbme(ctlr->pci);
547 /* enable interrupt */
550 ctlr->reg[IntMc] = ctlr->ints;
551 iunlock(&ctlr->intr);
553 /* enable controller */
554 ctlr->reg[CCfg] = 1 | (ctlr->mpsshift-12)<<7 | 6<<16 | 4<<20;
556 for(to = (ctlr->cap>>24) & 255; to >= 0; to--){
557 tsleep(&up->sleep, return0, nil, 500);
558 if((ctlr->reg[CSts] & 3) == 1)
561 if(ctlr->reg[CSts] & 2)
562 error("fatal controller status during initialization");
563 error("controller initialization timeout");
567 print("%s: using %d submit queues\n", name, ctlr->nsq);
581 for(p = nil; p = pcimatch(p, 0, 0);){
582 if(p->ccrb != 1 || p->ccru != 8 || p->ccrp != 2)
584 if(p->mem[0].size == 0 || (p->mem[0].bar & 1) != 0)
586 if((ctlr = malloc(sizeof(*ctlr))) == nil){
587 print("nvme: no memory for Ctlr\n");
592 ctlr->reg = vmap(p->mem[0].bar & ~0xF, p->mem[0].size);
593 if(ctlr->reg == nil){
594 print("nvme: can't vmap bar0\n");
597 vunmap(ctlr->reg, p->mem[0].size);
602 ctlr->cap = ctlr->reg[Cap0];
603 ctlr->cap |= (u64int)ctlr->reg[Cap1]<<32;
605 /* mask interrupts */
607 ctlr->reg[IntMs] = ~ctlr->ints;
609 /* disable controller */
612 if((ctlr->cap&(1ULL<<37)) == 0){
613 print("nvme: doesnt support NVM commactlr set: %ux\n",
614 (u32int)(ctlr->cap>>37) & 0xFF);
618 /* use 64K page size when possible */
619 ctlr->dstrd = (ctlr->cap >> 32) & 15;
620 for(i = (ctlr->cap >> 48) & 15; i < ((ctlr->cap >> 52) & 15); i++){
621 if(i >= 16-12) /* 64K */
624 ctlr->mpsshift = i+12;
625 ctlr->mps = 1 << ctlr->mpsshift;
649 for(ctlr = nvmepnpctlrs(); ctlr != nil; ctlr = ctlr->next){
650 if((s = malloc(sizeof(*s))) == nil)
671 nvmeenable, /* enable */
672 nvmedisable, /* disable */
674 nvmeverify, /* verify */
675 nvmeonline, /* online */