static int _sdinit(void) { ulong m; int i; SDev *sdev, *tail; SDunit *unit; /* * Probe all configured controllers and make a list * of devices found, accumulating a possible maximum number * of units attached and marking each device with an index * into the linear top-level directory array of units. */ tail = nil; for(i = 0; sdifc[i] != nil; i++){ if((sdev = sdifc[i]->pnp()) == nil) continue; if(sdlist != nil) tail->next = sdev; else sdlist = sdev; for(tail = sdev; tail->next != nil; tail = tail->next){ tail->index = sdnunit; sdnunit += tail->nunit; } tail->index = sdnunit; sdnunit += tail->nunit; } /* * Legacy and option code goes here. This will be hard... */ /* * The maximum number of possible units is known, allocate * placeholders for their datastructures; the units will be * probed and structures allocated when attached. * Allocate controller names for the different types. */ if(sdnunit == 0) return 0; if((sdunit = malloc(sdnunit*sizeof(SDunit*))) == nil) return 0; sddetach = _sddetach; for(i = 0; sdifc[i] != nil; i++){ if(sdifc[i]->id) sdifc[i]->id(sdlist); } if (0) sddump(); m = 0; cdmask = sdmask = 0; for(i=0; i<sdnunit && i < 32; i++) { unit = sdindex2unit(i); if(unit == nil) continue; sdinitpart(unit); partition(unit); if(unit->npart > 0){ /* BUG */ if((unit->inquiry[0] & 0x1F) == 0x05) cdmask |= (1<<i); else sdmask |= (1<<i); m |= (1<<i); } } //notesdinfo(); _sdmask = m; return m; }
static long sdbio(Chan* c, int write, char* a, long len, uvlong off) { int nchange; long l; uchar *b; SDpart *pp; SDunit *unit; SDev *sdev; ulong max, nb, offset; uvlong bno; sdev = sdgetdev(DEV(c->qid)); if(sdev == nil){ decref(&sdev->r); error(Enonexist); } unit = sdev->unit[UNIT(c->qid)]; if(unit == nil) error(Enonexist); nchange = 0; qlock(&unit->ctl); while(waserror()){ /* notification of media change; go around again */ if(strcmp(up->env->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){ sdinitpart(unit); continue; } /* other errors; give up */ qunlock(&unit->ctl); decref(&sdev->r); nexterror(); } pp = &unit->part[PART(c->qid)]; if(unit->vers+pp->vers != c->qid.vers) error(Echange); /* * Check the request is within bounds. * Removeable drives are locked throughout the I/O * in case the media changes unexpectedly. * Non-removeable drives are not locked during the I/O * to allow the hardware to optimise if it can; this is * a little fast and loose. * It's assumed that non-removeable media parameters * (sectors, secsize) can't change once the drive has * been brought online. */ bno = (off/unit->secsize) + pp->start; nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno; max = SDmaxio/unit->secsize; if(nb > max) nb = max; if(bno+nb > pp->end) nb = pp->end - bno; if(bno >= pp->end || nb == 0){ if(write) error(Eio); qunlock(&unit->ctl); decref(&sdev->r); poperror(); return 0; } if(!(unit->inquiry[1] & SDinq1removable)){ qunlock(&unit->ctl); poperror(); } b = sdmalloc(nb*unit->secsize); if(b == nil) error(Enomem); if(waserror()){ sdfree(b); if(!(unit->inquiry[1] & SDinq1removable)) decref(&sdev->r); /* gadverdamme! */ nexterror(); } offset = off%unit->secsize; if(offset+len > nb*unit->secsize) len = nb*unit->secsize - offset; if(write){ if(offset || (len%unit->secsize)){ l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno); if(l < 0) error(Eio); if(l < (nb*unit->secsize)){ nb = l/unit->secsize; l = nb*unit->secsize - offset; if(len > l) len = l; } } memmove(b+offset, a, len); l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno); if(l < 0) error(Eio); if(l < offset) len = 0; else if(len > l - offset) len = l - offset; } else{ l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno); if(l < 0) error(Eio); if(l < offset) len = 0; else if(len > l - offset) len = l - offset; memmove(a, b+offset, len); } sdfree(b); poperror(); if(unit->inquiry[1] & SDinq1removable){ qunlock(&unit->ctl); poperror(); } decref(&sdev->r); return len; }
static long sdwrite(Chan* c, void* a, long n, vlong off) { char *f0; int i; uvlong end, start; Cmdbuf *cb; SDifc *ifc; SDreq *req; SDunit *unit; SDev *sdev; switch(TYPE(c->qid)){ default: error(Eperm); case Qtopctl: cb = parsecmd(a, n); if(waserror()){ free(cb); nexterror(); } if(cb->nf == 0) error("empty control message"); f0 = cb->f[0]; cb->f++; cb->nf--; if(strcmp(f0, "config") == 0){ /* wormhole into ugly legacy interface */ legacytopctl(cb); poperror(); free(cb); break; } /* * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb), * where sdifc[i]->name=="ata" and cb contains the args. */ ifc = nil; sdev = nil; for(i=0; sdifc[i]; i++){ if(strcmp(sdifc[i]->name, f0) == 0){ ifc = sdifc[i]; sdev = nil; goto subtopctl; } } /* * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb), * where sdifc[i] and sdev match controller letter "1", * and cb contains the args. */ if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){ if((sdev = sdgetdev(f0[2])) != nil){ ifc = sdev->ifc; goto subtopctl; } } error("unknown interface"); subtopctl: if(waserror()){ if(sdev) decref(&sdev->r); nexterror(); } if(ifc->wtopctl) ifc->wtopctl(sdev, cb); else error(Ebadctl); poperror(); poperror(); if (sdev) decref(&sdev->r); free(cb); break; case Qctl: cb = parsecmd(a, n); sdev = sdgetdev(DEV(c->qid)); if(sdev == nil) error(Enonexist); unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->ctl); if(waserror()){ qunlock(&unit->ctl); decref(&sdev->r); free(cb); nexterror(); } if(unit->vers != c->qid.vers) error(Echange); if(cb->nf < 1) error(Ebadctl); if(strcmp(cb->f[0], "part") == 0){ if(cb->nf != 4) error(Ebadctl); if(unit->sectors == 0 && !sdinitpart(unit)) error(Eio); start = strtoull(cb->f[2], 0, 0); end = strtoull(cb->f[3], 0, 0); sdaddpart(unit, cb->f[1], start, end); } else if(strcmp(cb->f[0], "delpart") == 0){ if(cb->nf != 2 || unit->part == nil) error(Ebadctl); sddelpart(unit, cb->f[1]); } else if(unit->dev->ifc->wctl) unit->dev->ifc->wctl(unit, cb); else error(Ebadctl); qunlock(&unit->ctl); decref(&sdev->r); poperror(); free(cb); break; case Qraw: sdev = sdgetdev(DEV(c->qid)); if(sdev == nil) error(Enonexist); unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->raw); if(waserror()){ qunlock(&unit->raw); decref(&sdev->r); nexterror(); } switch(unit->state){ case Rawcmd: if(n < 6 || n > sizeof(req->cmd)) error(Ebadarg); if((req = malloc(sizeof(SDreq))) == nil) error(Enomem); req->unit = unit; memmove(req->cmd, a, n); req->clen = n; req->flags = SDnosense; req->status = ~0; unit->req = req; unit->state = Rawdata; break; case Rawstatus: unit->state = Rawcmd; free(unit->req); unit->req = nil; error(Ebadusefd); case Rawdata: unit->state = Rawstatus; unit->req->write = 1; n = sdrio(unit->req, a, n); } qunlock(&unit->raw); decref(&sdev->r); poperror(); break; case Qpart: return sdbio(c, 1, a, n, off); } return n; }
static int sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp) { Qid q; uvlong l; int i, r; SDpart *pp; SDunit *unit; SDev *sdev; switch(TYPE(c->qid)){ case Qtopdir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR); snprint(up->genbuf, sizeof up->genbuf, "#%C", sddevtab.dc); devdir(c, q, up->genbuf, 0, eve, 0555, dp); return 1; } if(s+Qtopbase < Qunitdir) return sd1gen(c, s+Qtopbase, dp); s -= (Qunitdir-Qtopbase); qlock(&devslock); for(i=0; i<nelem(devs); i++){ if(devs[i]){ if(s < devs[i]->nunit) break; s -= devs[i]->nunit; } } if(i == nelem(devs)){ /* Run off the end of the list */ qunlock(&devslock); return -1; } if((sdev = devs[i]) == nil){ qunlock(&devslock); return 0; } incref(&sdev->r); qunlock(&devslock); if((unit = sdev->unit[s]) == nil) if((unit = sdgetunit(sdev, s)) == nil){ decref(&sdev->r); return 0; } mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR); if(emptystr(unit->user)) kstrdup(&unit->user, eve); devdir(c, q, unit->name, 0, unit->user, unit->perm, dp); decref(&sdev->r); return 1; case Qunitdir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR); snprint(up->genbuf, sizeof up->genbuf, "#%C", sddevtab.dc); devdir(c, q, up->genbuf, 0, eve, 0555, dp); return 1; } if((sdev = sdgetdev(DEV(c->qid))) == nil){ devdir(c, c->qid, "unavailable", 0, eve, 0, dp); return 1; } unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->ctl); /* * Check for media change. * If one has already been detected, sectors will be zero. * If there is one waiting to be detected, online * will return > 1. * Online is a bit of a large hammer but does the job. */ if(unit->sectors == 0 || (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1)) sdinitpart(unit); i = s+Qunitbase; if(i < Qpart){ r = sd2gen(c, i, dp); qunlock(&unit->ctl); decref(&sdev->r); return r; } i -= Qpart; if(unit->part == nil || i >= unit->npart){ qunlock(&unit->ctl); decref(&sdev->r); break; } pp = &unit->part[i]; if(!pp->valid){ qunlock(&unit->ctl); decref(&sdev->r); return 0; } l = (pp->end - pp->start) * unit->secsize; mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart), unit->vers+pp->vers, QTFILE); if(emptystr(pp->user)) kstrdup(&pp->user, eve); devdir(c, q, pp->name, l, pp->user, pp->perm, dp); qunlock(&unit->ctl); decref(&sdev->r); return 1; case Qraw: case Qctl: case Qpart: if((sdev = sdgetdev(DEV(c->qid))) == nil){ devdir(c, q, "unavailable", 0, eve, 0, dp); return 1; } unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->ctl); r = sd2gen(c, TYPE(c->qid), dp); qunlock(&unit->ctl); decref(&sdev->r); return r; case Qtopctl: return sd1gen(c, TYPE(c->qid), dp); default: break; } return -1; }
static long sdread(Chan *c, void *a, long n, vlong off) { char *p, *e, *buf; SDpart *pp; SDunit *unit; SDev *sdev; ulong offset; int i, l, m, status; offset = off; switch(TYPE(c->qid)){ default: error(Eperm); case Qtopctl: m = 64*1024; /* room for register dumps */ p = buf = malloc(m); if(p == nil) error(Enomem); e = p + m; qlock(&devslock); for(i = 0; i < nelem(devs); i++){ sdev = devs[i]; if(sdev && sdev->ifc->rtopctl) p = sdev->ifc->rtopctl(sdev, p, e); } qunlock(&devslock); n = readstr(off, a, n, buf); free(buf); return n; case Qtopdir: case Qunitdir: return devdirread(c, a, n, 0, 0, sdgen); case Qctl: sdev = sdgetdev(DEV(c->qid)); if(sdev == nil) error(Enonexist); unit = sdev->unit[UNIT(c->qid)]; m = 16*1024; /* room for register dumps */ p = malloc(m); if(p == nil) error(Enomem); l = snprint(p, m, "inquiry %.48s\n", (char*)unit->inquiry+8); qlock(&unit->ctl); /* * If there's a device specific routine it must * provide all information pertaining to night geometry * and the garscadden trains. */ if(unit->dev->ifc->rctl) l += unit->dev->ifc->rctl(unit, p+l, m-l); if(unit->sectors == 0) sdinitpart(unit); if(unit->sectors){ if(unit->dev->ifc->rctl == nil) l += snprint(p+l, m-l, "geometry %llud %lud\n", unit->sectors, unit->secsize); pp = unit->part; for(i = 0; i < unit->npart; i++){ if(pp->valid) l += snprint(p+l, m-l, "part %s %llud %llud\n", pp->name, pp->start, pp->end); pp++; } } qunlock(&unit->ctl); decref(&sdev->r); l = readstr(offset, a, n, p); free(p); return l; case Qraw: sdev = sdgetdev(DEV(c->qid)); if(sdev == nil) error(Enonexist); unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->raw); if(waserror()){ qunlock(&unit->raw); decref(&sdev->r); nexterror(); } if(unit->state == Rawdata){ unit->state = Rawstatus; i = sdrio(unit->req, a, n); } else if(unit->state == Rawstatus){ status = unit->req->status; unit->state = Rawcmd; free(unit->req); unit->req = nil; i = readnum(0, a, n, status, NUMSIZE); } else i = 0; qunlock(&unit->raw); decref(&sdev->r); poperror(); return i; case Qpart: return sdbio(c, 0, a, n, off); } }