sdaoe.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       sdaoe.c (9903B)
       ---
            1 /*
            2  * aoe sd driver, copyright © 2007 coraid
            3  */
            4 
            5 #include "u.h"
            6 #include "lib.h"
            7 #include "mem.h"
            8 #include "dat.h"
            9 #include "fns.h"
           10 #include "io.h"
           11 #include "error.h"
           12 #include "sd.h"
           13 #include "netif.h"
           14 #include "aoe.h"
           15 
           16 extern        char        Echange[];
           17 extern        char        Enotup[];
           18 
           19 #define uprint(...)        snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
           20 
           21 enum {
           22         Nctlr        = 32,
           23         Maxpath        = 128,
           24 };
           25 
           26 enum {
           27         /* sync with ahci.h */
           28         Dllba         = 1<<0,
           29         Dsmart        = 1<<1,
           30         Dpower        = 1<<2,
           31         Dnop        = 1<<3,
           32         Datapi        = 1<<4,
           33         Datapi16= 1<<5,
           34 };
           35 
           36 static char *flagname[] = {
           37         "llba",
           38         "smart",
           39         "power",
           40         "nop",
           41         "atapi",
           42         "atapi16",
           43 };
           44 
           45 typedef struct Ctlr Ctlr;
           46 struct Ctlr{
           47         QLock        qlock;
           48 
           49         Ctlr        *next;
           50         SDunit        *unit;
           51 
           52         char        path[Maxpath];
           53         Chan        *c;
           54 
           55         ulong        vers;
           56         uchar        mediachange;
           57         uchar        flag;
           58         uchar        smart;
           59         uchar        smartrs;
           60         uchar        feat;
           61 
           62         uvlong        sectors;
           63         char        serial[20+1];
           64         char        firmware[8+1];
           65         char        model[40+1];
           66         char        ident[0x100];
           67 };
           68 
           69 static        Lock        ctlrlock;
           70 static        Ctlr        *head;
           71 static        Ctlr        *tail;
           72 
           73 SDifc sdaoeifc;
           74 
           75 static void
           76 idmove(char *p, ushort *a, int n)
           77 {
           78         int i;
           79         char *op, *e;
           80 
           81         op = p;
           82         for(i = 0; i < n/2; i++){
           83                 *p++ = a[i] >> 8;
           84                 *p++ = a[i];
           85         }
           86         *p = 0;
           87         while(p > op && *--p == ' ')
           88                 *p = 0;
           89         e = p;
           90         p = op;
           91         while(*p == ' ')
           92                 p++;
           93         memmove(op, p, n - (e - p));
           94 }
           95 
           96 static ushort
           97 gbit16(void *a)
           98 {
           99         uchar *i;
          100 
          101         i = a;
          102         return i[1] << 8 | i[0];
          103 }
          104 
          105 static ulong
          106 gbit32(void *a)
          107 {
          108         ulong j;
          109         uchar *i;
          110 
          111         i = a;
          112         j  = i[3] << 24;
          113         j |= i[2] << 16;
          114         j |= i[1] << 8;
          115         j |= i[0];
          116         return j;
          117 }
          118 
          119 static uvlong
          120 gbit64(void *a)
          121 {
          122         uchar *i;
          123 
          124         i = a;
          125         return (uvlong)gbit32(i+4)<<32 | gbit32(i);
          126 }
          127 
          128 static int
          129 identify(Ctlr *c, ushort *id)
          130 {
          131         int i;
          132         uchar oserial[21];
          133         uvlong osectors, s;
          134 
          135         osectors = c->sectors;
          136         memmove(oserial, c->serial, sizeof c->serial);
          137 
          138         c->feat &= ~(Dllba|Dpower|Dsmart|Dnop);
          139         i = gbit16(id+83) | gbit16(id+86);
          140         if(i & (1<<10)){
          141                 c->feat |= Dllba;
          142                 s = gbit64(id+100);
          143         }else
          144                 s = gbit32(id+60);
          145 
          146         i = gbit16(id+83);
          147         if((i>>14) == 1) {
          148                 if(i & (1<<3))
          149                         c->feat |= Dpower;
          150                 i = gbit16(id+82);
          151                 if(i & 1)
          152                         c->feat |= Dsmart;
          153                 if(i & (1<<14))
          154                         c->feat |= Dnop;
          155         }
          156 
          157         idmove(c->serial, id+10, 20);
          158         idmove(c->firmware, id+23, 8);
          159         idmove(c->model, id+27, 40);
          160 
          161         if((osectors == 0 || osectors != s) &&
          162             memcmp(oserial, c->serial, sizeof oserial) != 0){
          163                 c->sectors = s;
          164                 c->mediachange = 1;
          165                 c->vers++;
          166         }
          167         return 0;
          168 }
          169 
          170 /* must call with d qlocked */
          171 static int
          172 aoeidentify(Ctlr *d, SDunit *u)
          173 {
          174         Chan *c;
          175 
          176         c = nil;
          177         if(waserror()){
          178                 if(c)
          179                         cclose(c);
          180                 iprint("aoeidentify: %s\n", up->errstr);
          181                 nexterror();
          182         }
          183 
          184         uprint("%s/ident", d->path);
          185         c = namec(up->genbuf, Aopen, OREAD, 0);
          186         devtab[c->type]->read(c, d->ident, sizeof d->ident, 0);
          187 
          188         poperror();
          189         cclose(c);
          190 
          191         d->feat = 0;
          192         d->smart = 0;
          193         identify(d, (ushort*)d->ident);
          194 
          195         memset(u->inquiry, 0, sizeof u->inquiry);
          196         u->inquiry[2] = 2;
          197         u->inquiry[3] = 2;
          198         u->inquiry[4] = sizeof u->inquiry - 4;
          199         memmove(u->inquiry+8, d->model, 40);
          200 
          201         return 0;
          202 }
          203 
          204 static Ctlr*
          205 ctlrlookup(char *path)
          206 {
          207         Ctlr *c;
          208 
          209         lock(&ctlrlock);
          210         for(c = head; c; c = c->next)
          211                 if(strcmp(c->path, path) == 0)
          212                         break;
          213         unlock(&ctlrlock);
          214         return c;
          215 }
          216 
          217 static Ctlr*
          218 newctlr(char *path)
          219 {
          220         Ctlr *c;
          221 
          222         /* race? */
          223         if(ctlrlookup(path))
          224                 error(Eexist);
          225 
          226         if((c = malloc(sizeof *c)) == nil)
          227                 return 0;
          228         kstrcpy(c->path, path, sizeof c->path);
          229         lock(&ctlrlock);
          230         if(head != nil)
          231                 tail->next = c;
          232         else
          233                 head = c;
          234         tail = c;
          235         unlock(&ctlrlock);
          236         return c;
          237 }
          238 
          239 static void
          240 delctlr(Ctlr *c)
          241 {
          242         Ctlr *x, *prev;
          243 
          244         lock(&ctlrlock);
          245 
          246         for(prev = 0, x = head; x; prev = x, x = c->next)
          247                 if(strcmp(c->path, x->path) == 0)
          248                         break;
          249         if(x == 0){
          250                 unlock(&ctlrlock);
          251                 error(Enonexist);
          252         }
          253 
          254         if(prev)
          255                 prev->next = x->next;
          256         else
          257                 head = x->next;
          258         if(x->next == nil)
          259                 tail = prev;
          260         unlock(&ctlrlock);
          261 
          262         if(x->c)
          263                 cclose(x->c);
          264         free(x);
          265 }
          266 
          267 static SDev*
          268 aoeprobe(char *path, SDev *s)
          269 {
          270         int n, i;
          271         char *p;
          272         Chan *c;
          273         Ctlr *ctlr;
          274 
          275         if((p = strrchr(path, '/')) == 0)
          276                 error(Ebadarg);
          277         *p = 0;
          278         uprint("%s/ctl", path);
          279         *p = '/';
          280 
          281         c = namec(up->genbuf, Aopen, OWRITE, 0);
          282         if(waserror()) {
          283                 cclose(c);
          284                 nexterror();
          285         }
          286         n = uprint("discover %s", p+1);
          287         devtab[c->type]->write(c, up->genbuf, n, 0);
          288         poperror();
          289         cclose(c);
          290 
          291         for(i = 0;; i += 200){
          292                 if(i > 8000 || waserror())
          293                         error(Etimedout);
          294                 tsleep(&up->sleep, return0, 0, 200);
          295                 poperror();
          296 
          297                 uprint("%s/ident", path);
          298                 if(waserror())
          299                         continue;
          300                 c = namec(up->genbuf, Aopen, OREAD, 0);
          301                 poperror();
          302                 cclose(c);
          303 
          304                 ctlr = newctlr(path);
          305                 break;
          306         }
          307 
          308         if(s == nil && (s = malloc(sizeof *s)) == nil)
          309                 return nil;
          310         s->ctlr = ctlr;
          311         s->ifc = &sdaoeifc;
          312         s->nunit = 1;
          313         return s;
          314 }
          315 
          316 static char         *probef[32];
          317 static int         nprobe;
          318 
          319 static int
          320 pnpprobeid(char *s)
          321 {
          322         int id;
          323 
          324         if(strlen(s) < 2)
          325                 return 0;
          326         id = 'e';
          327         if(s[1] == '!')
          328                 id = s[0];
          329         return id;
          330 }
          331 
          332 static SDev*
          333 aoepnp(void)
          334 {
          335         int i, id;
          336         char *p;
          337         SDev *h, *t, *s;
          338 
          339 //        if((p = getconf("aoedev")) == 0)
          340         if(1)
          341                 return 0;
          342         nprobe = tokenize(p, probef, nelem(probef));
          343         h = t = 0;
          344         for(i = 0; i < nprobe; i++){
          345                 id = pnpprobeid(probef[i]);
          346                 if(id == 0)
          347                         continue;
          348                 s = malloc(sizeof *s);
          349                 if(s == nil)
          350                         break;
          351                 s->ctlr = 0;
          352                 s->idno = id;
          353                 s->ifc = &sdaoeifc;
          354                 s->nunit = 1;
          355 
          356                 if(h)
          357                         t->next = s;
          358                 else
          359                         h = s;
          360                 t = s;
          361         }
          362         return h;
          363 }
          364 
          365 static Ctlr*
          366 pnpprobe(SDev *sd)
          367 {
          368         int j;
          369         char *p;
          370         static int i;
          371 
          372         if(i > nprobe)
          373                 return 0;
          374         p = probef[i++];
          375         if(strlen(p) < 2)
          376                 return 0;
          377         if(p[1] == '!')
          378                 p += 2;
          379 
          380         for(j = 0;; j += 200){
          381                 if(j > 8000){
          382                         print("#æ: pnpprobe: %s: %s\n", probef[i-1], up->errstr);
          383                         return 0;
          384                 }
          385                 if(waserror()){
          386                         tsleep(&up->sleep, return0, 0, 200);
          387                         continue;
          388                 }
          389                 sd = aoeprobe(p, sd);
          390                 poperror();
          391                 break;
          392         }
          393         print("#æ: pnpprobe establishes %sin %dms\n", probef[i-1], j);
          394         return sd->ctlr;
          395 }
          396 
          397 
          398 static int
          399 aoeverify(SDunit *u)
          400 {
          401         SDev *s;
          402         Ctlr *c;
          403 
          404         s = u->dev;
          405         c = s->ctlr;
          406         if(c == nil && (s->ctlr = c = pnpprobe(s)) == nil)
          407                 return 0;
          408         c->mediachange = 1;
          409         return 1;
          410 }
          411 
          412 static int
          413 aoeconnect(SDunit *u, Ctlr *c)
          414 {
          415         QLOCK(c);
          416         if(waserror()){
          417                 QUNLOCK(c);
          418                 return -1;
          419         }
          420 
          421         aoeidentify(u->dev->ctlr, u);
          422         if(c->c)
          423                 cclose(c->c);
          424         c->c = 0;
          425         uprint("%s/data", c->path);
          426         c->c = namec(up->genbuf, Aopen, ORDWR, 0);
          427         QUNLOCK(c);
          428         poperror();
          429 
          430         return 0;
          431 }
          432 
          433 static int
          434 aoeonline(SDunit *u)
          435 {
          436         Ctlr *c;
          437         int r;
          438 
          439         c = u->dev->ctlr;
          440         r = 0;
          441 
          442         if((c->feat&Datapi) && c->mediachange){
          443                 if(aoeconnect(u, c) == 0 && (r = scsionline(u)) > 0)
          444                         c->mediachange = 0;
          445                 return r;
          446         }
          447 
          448         if(c->mediachange){
          449                 if(aoeconnect(u, c) == -1)
          450                         return 0;
          451                 r = 2;
          452                 c->mediachange = 0;
          453                 u->sectors = c->sectors;
          454                 u->secsize = Aoesectsz;
          455         } else
          456                 r = 1;
          457 
          458         return r;
          459 }
          460 
          461 static int
          462 aoerio(SDreq *r)
          463 {
          464         int i, count;
          465         uvlong lba;
          466         char *name;
          467         uchar *cmd;
          468         long (*rio)(Chan*, void*, long, vlong);
          469         Ctlr *c;
          470         SDunit *unit;
          471 
          472         unit = r->unit;
          473         c = unit->dev->ctlr;
          474 //        if(c->feat & Datapi)
          475 //                return aoeriopkt(r, d);
          476 
          477         cmd = r->cmd;
          478         name = unit->perm.name;
          479 
          480         if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
          481 //                QLOCK(c);
          482 //                i = flushcache();
          483 //                QUNLOCK(c);
          484 //                if(i == 0)
          485 //                        return sdsetsense(r, SDok, 0, 0, 0);
          486                 return sdsetsense(r, SDcheck, 3, 0xc, 2);
          487         }
          488 
          489         if((i = sdfakescsi(r, c->ident, sizeof c->ident)) != SDnostatus){
          490                 r->status = i;
          491                 return i;
          492         }
          493 
          494         switch(*cmd){
          495         case 0x88:
          496         case 0x28:
          497                 rio = devtab[c->c->type]->read;
          498                 break;
          499         case 0x8a:
          500         case 0x2a:
          501                 rio = devtab[c->c->type]->write;
          502                 break;
          503         default:
          504                 print("%s: bad cmd %#.2ux\n", name, cmd[0]);
          505                 r->status = SDcheck;
          506                 return SDcheck;
          507         }
          508 
          509         if(r->data == nil)
          510                 return SDok;
          511 
          512         if(r->clen == 16){
          513                 if(cmd[2] || cmd[3])
          514                         return sdsetsense(r, SDcheck, 3, 0xc, 2);
          515                 lba = (uvlong)cmd[4]<<40 | (uvlong)cmd[5]<<32;
          516                 lba |=   cmd[6]<<24 |  cmd[7]<<16 |  cmd[8]<<8 | cmd[9];
          517                 count = cmd[10]<<24 | cmd[11]<<16 | cmd[12]<<8 | cmd[13];
          518         }else{
          519                 lba  = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5];
          520                 count = cmd[7]<<8 | cmd[8];
          521         }
          522 
          523         count *= Aoesectsz;
          524 
          525         if(r->dlen < count)
          526                 count = r->dlen & ~0x1ff;
          527 
          528         if(waserror()){
          529                 if(strcmp(up->errstr, Echange) == 0 ||
          530                     strcmp(up->errstr, Enotup) == 0)
          531                         unit->sectors = 0;
          532                 nexterror();
          533         }
          534         r->rlen = rio(c->c, r->data, count, Aoesectsz * lba);
          535         poperror();
          536         r->status = SDok;
          537         return SDok;
          538 }
          539 
          540 static char *smarttab[] = {
          541         "unset",
          542         "error",
          543         "threshold exceeded",
          544         "normal"
          545 };
          546 
          547 static char *
          548 pflag(char *s, char *e, uchar f)
          549 {
          550         uchar i, m;
          551 
          552         for(i = 0; i < 8; i++){
          553                 m = 1 << i;
          554                 if(f & m)
          555                         s = seprint(s, e, "%s ", flagname[i]);
          556         }
          557         return seprint(s, e, "\n");
          558 }
          559 
          560 static int
          561 aoerctl(SDunit *u, char *p, int l)
          562 {
          563         Ctlr *c;
          564         char *e, *op;
          565 
          566         if((c = u->dev->ctlr) == nil)
          567                 return 0;
          568         e = p+l;
          569         op = p;
          570 
          571         p = seprint(p, e, "model\t%s\n", c->model);
          572         p = seprint(p, e, "serial\t%s\n", c->serial);
          573         p = seprint(p, e, "firm        %s\n", c->firmware);
          574         if(c->smartrs == 0xff)
          575                 p = seprint(p, e, "smart\tenable error\n");
          576         else if(c->smartrs == 0)
          577                 p = seprint(p, e, "smart\tdisabled\n");
          578         else
          579                 p = seprint(p, e, "smart\t%s\n", smarttab[c->smart]);
          580         p = seprint(p, e, "flag        ");
          581         p = pflag(p, e, c->feat);
          582         p = seprint(p, e, "geometry %llud %d\n", c->sectors, Aoesectsz);
          583         return p-op;
          584 }
          585 
          586 static int
          587 aoewctl(SDunit *d1, Cmdbuf *cmd)
          588 {
          589         cmderror(cmd, Ebadarg);
          590         return 0;
          591 }
          592 
          593 static SDev*
          594 aoeprobew(DevConf *c)
          595 {
          596         char *p;
          597 
          598         p = strchr(c->type, '/');
          599         if(p == nil || strlen(p) > Maxpath - 11)
          600                 error(Ebadarg);
          601         if(p[1] == '#')
          602                 p++;                        /* hack */
          603         if(ctlrlookup(p))
          604                 error(Einuse);
          605         return aoeprobe(p, 0);
          606 }
          607 
          608 static void
          609 aoeclear(SDev *s)
          610 {
          611         delctlr((Ctlr *)s->ctlr);
          612 }
          613 
          614 static char*
          615 aoertopctl(SDev *s, char *p, char *e)
          616 {
          617         Ctlr *c;
          618 
          619         c = s->ctlr;
          620         return seprint(p, e, "%s aoe %s\n", s->name, c->path);
          621 }
          622 
          623 static int
          624 aoewtopctl(SDev *d1, Cmdbuf *cmd)
          625 {
          626         switch(cmd->nf){
          627         default:
          628                 cmderror(cmd, Ebadarg);
          629         }
          630         return 0;
          631 }
          632 
          633 SDifc sdaoeifc = {
          634         "aoe",
          635 
          636         aoepnp,
          637         nil,                /* legacy */
          638         nil,                /* enable */
          639         nil,                /* disable */
          640 
          641         aoeverify,
          642         aoeonline,
          643         aoerio,
          644         aoerctl,
          645         aoewctl,
          646 
          647         scsibio,
          648         aoeprobew,        /* probe */
          649         aoeclear,        /* clear */
          650         aoertopctl,
          651         aoewtopctl,
          652 };