The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pc/sdiahci.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * intel/amd ahci sata controller
    3  * copyright © 2007-8 coraid, inc.
    4  */
    5 
    6 #include "u.h"
    7 #include "../port/lib.h"
    8 #include "mem.h"
    9 #include "dat.h"
   10 #include "fns.h"
   11 #include "io.h"
   12 #include "../port/error.h"
   13 #include "../port/sd.h"
   14 #include "ahci.h"
   15 
   16 #define dprint(...)     if(debug)       iprint(__VA_ARGS__); else USED(debug)
   17 #define idprint(...)    if(prid)        iprint(__VA_ARGS__);  else USED(prid)
   18 #define aprint(...)     if(datapi)      iprint(__VA_ARGS__);  else USED(datapi)
   19 #define Tname(c)        tname[(c)->type]
   20 
   21 enum {
   22         NCtlr   = 4,
   23         NCtlrdrv= 32,
   24         NDrive  = NCtlr*NCtlrdrv,
   25 
   26         Read    = 0,
   27         Write,
   28 };
   29 
   30 /* pci space configuration */
   31 enum {
   32         Pmap    = 0x90,
   33         Ppcs    = 0x91,
   34         Prev    = 0xa8,
   35 };
   36 
   37 enum {
   38         Tesb,
   39         Tich,
   40         Tsb600,
   41         Tunk,
   42 };
   43 
   44 #define Intel(x)        ((x)->pci->vid == 0x8086)
   45 
   46 static char *tname[] = {
   47         "63xxesb",
   48         "ich",
   49         "sb600",
   50         "unk",
   51 };
   52 
   53 enum {
   54         Dnull,
   55         Dmissing,
   56         Dnew,
   57         Dready,
   58         Derror,
   59         Dreset,
   60         Doffline,
   61         Dportreset,
   62         Dlast,
   63 };
   64 
   65 static char *diskstates[Dlast] = {
   66         "null",
   67         "missing",
   68         "new",
   69         "ready",
   70         "error",
   71         "reset",
   72         "offline",
   73         "portreset",
   74 };
   75 
   76 extern SDifc sdiahciifc;
   77 typedef struct Ctlr Ctlr;
   78 
   79 enum {
   80         DMautoneg,
   81         DMsatai,
   82         DMsataii,
   83 };
   84 
   85 static char *modename[] = {
   86         "auto",
   87         "satai",
   88         "sataii",
   89 };
   90 
   91 static char *flagname[] = {
   92         "llba",
   93         "smart",
   94         "power",
   95         "nop",
   96         "atapi",
   97         "atapi16",
   98 };
   99 
  100 typedef struct {
  101         Lock;
  102 
  103         Ctlr    *ctlr;
  104         SDunit  *unit;
  105         char    name[10];
  106         Aport   *port;
  107         Aportm  portm;
  108         Aportc  portc;          /* redundant ptr to port and portm */
  109 
  110         uchar   mediachange;
  111         uchar   state;
  112         uchar   smartrs;
  113 
  114         uvlong  sectors;
  115         ulong   intick;         /* start tick of current transfer */
  116         ulong   lastseen;
  117         int     wait;
  118         uchar   mode;           /* DMautoneg, satai or sataii */
  119         uchar   active;
  120 
  121         char    serial[20+1];
  122         char    firmware[8+1];
  123         char    model[40+1];
  124 
  125         ushort  info[0x200];
  126 
  127         int     driveno;        /* ctlr*NCtlrdrv + unit */
  128         /* controller port # != driveno when not all ports are enabled */
  129         int     portno;
  130 } Drive;
  131 
  132 struct Ctlr {
  133         Lock;
  134 
  135         int     type;
  136         int     enabled;
  137         SDev    *sdev;
  138         Pcidev  *pci;
  139 
  140         uchar   *mmio;
  141         ulong   *lmmio;
  142         Ahba    *hba;
  143 
  144         Drive   rawdrive[NCtlrdrv];
  145         Drive*  drive[NCtlrdrv];
  146         int     ndrive;
  147         int     mport;
  148 };
  149 
  150 static  Ctlr    iactlr[NCtlr];
  151 static  SDev    sdevs[NCtlr];
  152 static  int     niactlr;
  153 
  154 static  Drive   *iadrive[NDrive];
  155 static  int     niadrive;
  156 
  157 /* these are fiddled in iawtopctl() */
  158 static  int     debug;
  159 static  int     prid = 1;
  160 static  int     datapi;
  161 
  162 static char stab[] = {
  163 [0]     'i', 'm',
  164 [8]     't', 'c', 'p', 'e',
  165 [16]    'N', 'I', 'W', 'B', 'D', 'C', 'H', 'S', 'T', 'F', 'X'
  166 };
  167 
  168 static void
  169 serrstr(ulong r, char *s, char *e)
  170 {
  171         int i;
  172 
  173         e -= 3;
  174         for(i = 0; i < nelem(stab) && s < e; i++)
  175                 if(r & (1<<i) && stab[i]){
  176                         *s++ = stab[i];
  177                         if(SerrBad & (1<<i))
  178                                 *s++ = '*';
  179                 }
  180         *s = 0;
  181 }
  182 
  183 static char ntab[] = "0123456789abcdef";
  184 
  185 static void
  186 preg(uchar *reg, int n)
  187 {
  188         int i;
  189         char buf[25*3+1], *e;
  190 
  191         e = buf;
  192         for(i = 0; i < n; i++){
  193                 *e++ = ntab[reg[i]>>4];
  194                 *e++ = ntab[reg[i]&0xf];
  195                 *e++ = ' ';
  196         }
  197         *e++ = '\n';
  198         *e = 0;
  199         dprint(buf);
  200 }
  201 
  202 static void
  203 dreg(char *s, Aport *p)
  204 {
  205         dprint("ahci: %stask=%lux; cmd=%lux; ci=%lux; is=%lux\n",
  206                 s, p->task, p->cmd, p->ci, p->isr);
  207 }
  208 
  209 static void
  210 esleep(int ms)
  211 {
  212         if(waserror())
  213                 return;
  214         tsleep(&up->sleep, return0, 0, ms);
  215         poperror();
  216 }
  217 
  218 typedef struct {
  219         Aport   *p;
  220         int     i;
  221 }Asleep;
  222 
  223 static int
  224 ahciclear(void *v)
  225 {
  226         Asleep *s;
  227 
  228         s = v;
  229         return (s->p->ci & s->i) == 0;
  230 }
  231 
  232 static void
  233 aesleep(Aportm *m, Asleep *a, int ms)
  234 {
  235         if(waserror())
  236                 return;
  237         tsleep(m, ahciclear, a, ms);
  238         poperror();
  239 }
  240 
  241 static int
  242 ahciwait(Aportc *c, int ms)
  243 {
  244         Asleep as;
  245         Aport *p;
  246 
  247         p = c->p;
  248         p->ci = 1;
  249         as.p = p;
  250         as.i = 1;
  251         aesleep(c->m, &as, ms);
  252         if((p->task&1) == 0 && p->ci == 0)
  253                 return 0;
  254         dreg("ahciwait timeout ", c->p);
  255         return -1;
  256 }
  257 
  258 static int
  259 nop(Aportc *pc)
  260 {
  261         uchar *c;
  262         Actab *t;
  263         Alist *l;
  264 
  265         if((pc->m->feat & Dnop) == 0)
  266                 return -1;
  267 
  268         t = pc->m->ctab;
  269         c = t->cfis;
  270 
  271         memset(c, 0, 0x20);
  272         c[0] = 0x27;
  273         c[1] = 0x80;
  274         c[2] = 0x00;
  275         c[7] = 0xa0;            /* obsolete device bits */
  276 
  277         l = pc->m->list;
  278         l->flags = Lwrite | 0x5;
  279         l->len = 0;
  280         l->ctab = PCIWADDR(t);
  281         l->ctabhi = 0;
  282 
  283         return ahciwait(pc, 3*1000);
  284 }
  285 
  286 static int
  287 setfeatures(Aportc *pc, uchar f)
  288 {
  289         uchar *c;
  290         Actab *t;
  291         Alist *l;
  292 
  293         t = pc->m->ctab;
  294         c = t->cfis;
  295 
  296         memset(c, 0, 0x20);
  297         c[0] = 0x27;
  298         c[1] = 0x80;
  299         c[2] = 0xef;
  300         c[3] = f;
  301         c[7] = 0xa0;            /* obsolete device bits */
  302 
  303         l = pc->m->list;
  304         l->flags = Lwrite | 0x5;
  305         l->len = 0;
  306         l->ctab = PCIWADDR(t);
  307         l->ctabhi = 0;
  308 
  309         return ahciwait(pc, 3*1000);
  310 }
  311 
  312 static int
  313 setudmamode(Aportc *pc, uchar f)
  314 {
  315         uchar *c;
  316         Actab *t;
  317         Alist *l;
  318 
  319         /* hack */
  320         if((pc->p->sig >> 16) == 0xeb14)
  321                 return 0;
  322 
  323         t = pc->m->ctab;
  324         c = t->cfis;
  325 
  326         memset(c, 0, 0x20);
  327         c[0] = 0x27;
  328         c[1] = 0x80;
  329         c[2] = 0xef;
  330         c[3] = 3;               /* set transfer mode */
  331         c[7] = 0xa0;            /* obsolete device bits */
  332         c[12] = 0x40 | f;       /* sector count */
  333 
  334         l = pc->m->list;
  335         l->flags = Lwrite | 0x5;
  336         l->len = 0;
  337         l->ctab = PCIWADDR(t);
  338         l->ctabhi = 0;
  339 
  340         return ahciwait(pc, 3*1000);
  341 }
  342 
  343 static void
  344 asleep(int ms)
  345 {
  346         if(up == nil)
  347                 delay(ms);
  348         else
  349                 esleep(ms);
  350 }
  351 
  352 static int
  353 ahciportreset(Aportc *c)
  354 {
  355         ulong *cmd, i;
  356         Aport *p;
  357 
  358         p = c->p;
  359         cmd = &p->cmd;
  360         *cmd &= ~(Afre|Ast);
  361         for(i = 0; i < 500; i += 25){
  362                 if((*cmd&Acr) == 0)
  363                         break;
  364                 asleep(25);
  365         }
  366         p->sctl = 1|(p->sctl&~7);
  367         delay(1);
  368         p->sctl &= ~7;
  369         return 0;
  370 }
  371 
  372 static int
  373 smart(Aportc *pc, int n)
  374 {
  375         uchar *c;
  376         Actab *t;
  377         Alist *l;
  378 
  379         if((pc->m->feat&Dsmart) == 0)
  380                 return -1;
  381 
  382         t = pc->m->ctab;
  383         c = t->cfis;
  384 
  385         memset(c, 0, 0x20);
  386         c[0] = 0x27;
  387         c[1] = 0x80;
  388         c[2] = 0xb0;
  389         c[3] = 0xd8 + n;        /* able smart */
  390         c[5] = 0x4f;
  391         c[6] = 0xc2;
  392         c[7] = 0xa0;
  393 
  394         l = pc->m->list;
  395         l->flags = Lwrite | 0x5;
  396         l->len = 0;
  397         l->ctab = PCIWADDR(t);
  398         l->ctabhi = 0;
  399 
  400         if(ahciwait(pc, 1000) == -1 || pc->p->task & (1|32)){
  401                 dprint("ahci: smart fail %lux\n", pc->p->task);
  402 //              preg(pc->m->fis.r, 20);
  403                 return -1;
  404         }
  405         if(n)
  406                 return 0;
  407         return 1;
  408 }
  409 
  410 static int
  411 smartrs(Aportc *pc)
  412 {
  413         uchar *c;
  414         Actab *t;
  415         Alist *l;
  416 
  417         t = pc->m->ctab;
  418         c = t->cfis;
  419 
  420         memset(c, 0, 0x20);
  421         c[0] = 0x27;
  422         c[1] = 0x80;
  423         c[2] = 0xb0;
  424         c[3] = 0xda;            /* return smart status */
  425         c[5] = 0x4f;
  426         c[6] = 0xc2;
  427         c[7] = 0xa0;
  428 
  429         l = pc->m->list;
  430         l->flags = Lwrite | 0x5;
  431         l->len = 0;
  432         l->ctab = PCIWADDR(t);
  433         l->ctabhi = 0;
  434 
  435         c = pc->m->fis.r;
  436         if(ahciwait(pc, 1000) == -1 || pc->p->task & (1|32)){
  437                 dprint("ahci: smart fail %lux\n", pc->p->task);
  438                 preg(c, 20);
  439                 return -1;
  440         }
  441         if(c[5] == 0x4f && c[6] == 0xc2)
  442                 return 1;
  443         return 0;
  444 }
  445 
  446 static int
  447 ahciflushcache(Aportc *pc)
  448 {
  449         uchar *c, llba;
  450         Actab *t;
  451         Alist *l;
  452         static uchar tab[2] = {0xe7, 0xea};
  453 
  454         llba = pc->m->feat&Dllba? 1: 0;
  455         t = pc->m->ctab;
  456         c = t->cfis;
  457 
  458         memset(c, 0, 0x20);
  459         c[0] = 0x27;
  460         c[1] = 0x80;
  461         c[2] = tab[llba];
  462         c[7] = 0xa0;
  463 
  464         l = pc->m->list;
  465         l->flags = Lwrite | 0x5;
  466         l->len = 0;
  467         l->ctab = PCIWADDR(t);
  468         l->ctabhi = 0;
  469 
  470         if(ahciwait(pc, 60000) == -1 || pc->p->task & (1|32)){
  471                 dprint("ahciflushcache: fail %lux\n", pc->p->task);
  472 //              preg( pc->m->fis.r, 20);
  473                 return -1;
  474         }
  475         return 0;
  476 }
  477 
  478 static ushort
  479 gbit16(void *a)
  480 {
  481         ushort j;
  482         uchar *i;
  483 
  484         i = a;
  485         j  = i[1] << 8;
  486         j |= i[0];
  487         return j;
  488 }
  489 
  490 static ulong
  491 gbit32(void *a)
  492 {
  493         ulong j;
  494         uchar *i;
  495 
  496         i = a;
  497         j  = i[3] << 24;
  498         j |= i[2] << 16;
  499         j |= i[1] << 8;
  500         j |= i[0];
  501         return j;
  502 }
  503 
  504 static uvlong
  505 gbit64(void *a)
  506 {
  507         uchar *i;
  508 
  509         i = a;
  510         return (uvlong)gbit32(i+4) << 32 | gbit32(a);
  511 }
  512 
  513 static int
  514 ahciidentify0(Aportc *pc, void *id, int atapi)
  515 {
  516         uchar *c;
  517         Actab *t;
  518         Alist *l;
  519         Aprdt *p;
  520         static uchar tab[] = { 0xec, 0xa1, };
  521 
  522         t = pc->m->ctab;
  523         c = t->cfis;
  524 
  525         memset(c, 0, 0x20);
  526         c[0] = 0x27;
  527         c[1] = 0x80;
  528         c[2] = tab[atapi];
  529         c[7] = 0xa0;            /* obsolete device bits */
  530 
  531         l = pc->m->list;
  532         l->flags = 1<<16 | 0x5;
  533         l->len = 0;
  534         l->ctab = PCIWADDR(t);
  535         l->ctabhi = 0;
  536 
  537         memset(id, 0, 0x100);
  538         p = &t->prdt;
  539         p->dba = PCIWADDR(id);
  540         p->dbahi = 0;
  541         p->count = 1<<31 | (0x200-2) | 1;
  542 
  543         return ahciwait(pc, 3*1000);
  544 }
  545 
  546 static vlong
  547 ahciidentify(Aportc *pc, ushort *id)
  548 {
  549         int i, sig;
  550         vlong s;
  551         Aportm *m;
  552 
  553         m = pc->m;
  554         m->feat = 0;
  555         m->smart = 0;
  556         i = 0;
  557         sig = pc->p->sig >> 16;
  558         if(sig == 0xeb14){
  559                 m->feat |= Datapi;
  560                 i = 1;
  561         }
  562         if(ahciidentify0(pc, id, i) == -1)
  563                 return -1;
  564 
  565         i = gbit16(id+83) | gbit16(id+86);
  566         if(i & (1<<10)){
  567                 m->feat |= Dllba;
  568                 s = gbit64(id+100);
  569         }else
  570                 s = gbit32(id+60);
  571 
  572         if(m->feat&Datapi){
  573                 i = gbit16(id+0);
  574                 if(i&1)
  575                         m->feat |= Datapi16;
  576         }
  577 
  578         i = gbit16(id+83);
  579         if((i>>14) == 1) {
  580                 if(i & (1<<3))
  581                         m->feat |= Dpower;
  582                 i = gbit16(id+82);
  583                 if(i & 1)
  584                         m->feat |= Dsmart;
  585                 if(i & (1<<14))
  586                         m->feat |= Dnop;
  587         }
  588         return s;
  589 }
  590 
  591 static int
  592 ahciquiet(Aport *a)
  593 {
  594         ulong *p, i;
  595 
  596         p = &a->cmd;
  597         *p &= ~Ast;
  598         for(i = 0; i < 500; i += 50){
  599                 if((*p & Acr) == 0)
  600                         goto stop;
  601                 asleep(50);
  602         }
  603         return -1;
  604 stop:
  605         if((a->task & (ASdrq|ASbsy)) == 0){
  606                 *p |= Ast;
  607                 return 0;
  608         }
  609 
  610         *p |= Aclo;
  611         for(i = 0; i < 500; i += 50){
  612                 if((*p & Aclo) == 0)
  613                         goto stop1;
  614                 asleep(50);
  615         }
  616         return -1;
  617 stop1:
  618         /* extra check */
  619         dprint("ahci: clo clear %lx\n", a->task);
  620         if(a->task & ASbsy)
  621                 return -1;
  622         *p |= Ast;
  623         return 0;
  624 }
  625 
  626 static int
  627 ahcicomreset(Aportc *pc)
  628 {
  629         uchar *c;
  630         Actab *t;
  631         Alist *l;
  632 
  633         dprint("ahcicomreset\n");
  634         dreg("ahci: comreset ", pc->p);
  635         if(ahciquiet(pc->p) == -1){
  636                 dprint("ahciquiet failed\n");
  637                 return -1;
  638         }
  639         dreg("comreset ", pc->p);
  640 
  641         t = pc->m->ctab;
  642         c = t->cfis;
  643 
  644         memset(c, 0, 0x20);
  645         c[0] = 0x27;
  646         c[1] = 0x00;
  647         c[7] = 0xa0;            /* obsolete device bits */
  648         c[15] = 1<<2;           /* srst */
  649 
  650         l = pc->m->list;
  651         l->flags = Lclear | Lreset | 0x5;
  652         l->len = 0;
  653         l->ctab = PCIWADDR(t);
  654         l->ctabhi = 0;
  655 
  656         if(ahciwait(pc, 500) == -1){
  657                 dprint("ahcicomreset: first command failed\n");
  658                 return -1;
  659         }
  660         microdelay(250);
  661         dreg("comreset ", pc->p);
  662 
  663         memset(c, 0, 0x20);
  664         c[0] = 0x27;
  665         c[1] = 0x00;
  666         c[7] = 0xa0;            /* obsolete device bits */
  667 
  668         l = pc->m->list;
  669         l->flags = Lwrite | 0x5;
  670         l->len = 0;
  671         l->ctab = PCIWADDR(t);
  672         l->ctabhi = 0;
  673 
  674         if(ahciwait(pc, 150) == -1){
  675                 dprint("ahcicomreset: second command failed\n");
  676                 return -1;
  677         }
  678         dreg("comreset ", pc->p);
  679         return 0;
  680 }
  681 
  682 static int
  683 ahciidle(Aport *port)
  684 {
  685         ulong *p, i, r;
  686 
  687         p = &port->cmd;
  688         if((*p & Arun) == 0)
  689                 return 0;
  690         *p &= ~Ast;
  691         r = 0;
  692         for(i = 0; i < 500; i += 25){
  693                 if((*p & Acr) == 0)
  694                         goto stop;
  695                 asleep(25);
  696         }
  697         r = -1;
  698 stop:
  699         if((*p & Afre) == 0)
  700                 return r;
  701         *p &= ~Afre;
  702         for(i = 0; i < 500; i += 25){
  703                 if((*p & Afre) == 0)
  704                         return 0;
  705                 asleep(25);
  706         }
  707         return -1;
  708 }
  709 
  710 /*
  711  * § 6.2.2.1  first part; comreset handled by reset disk.
  712  *      - remainder is handled by configdisk.
  713  *      - ahcirecover is a quick recovery from a failed command.
  714  */
  715 static int
  716 ahciswreset(Aportc *pc)
  717 {
  718         int i;
  719 
  720         i = ahciidle(pc->p);
  721         pc->p->cmd |= Afre;
  722         if(i == -1)
  723                 return -1;
  724         if(pc->p->task & (ASdrq|ASbsy))
  725                 return -1;
  726         return 0;
  727 }
  728 
  729 static int
  730 ahcirecover(Aportc *pc)
  731 {
  732         ahciswreset(pc);
  733         pc->p->cmd |= Ast;
  734         if(setudmamode(pc, 5) == -1)
  735                 return -1;
  736         return 0;
  737 }
  738 
  739 static void*
  740 malign(int size, int align)
  741 {
  742         void *v;
  743 
  744         v = xspanalloc(size, align, 0);
  745         memset(v, 0, size);
  746         return v;
  747 }
  748 
  749 static void
  750 setupfis(Afis *f)
  751 {
  752         f->base = malign(0x100, 0x100);
  753         f->d = f->base + 0;
  754         f->p = f->base + 0x20;
  755         f->r = f->base + 0x40;
  756         f->u = f->base + 0x60;
  757         f->devicebits = (ulong*)(f->base + 0x58);
  758 }
  759 
  760 static void
  761 ahciwakeup(Aport *p)
  762 {
  763         ushort s;
  764 
  765         s = p->sstatus;
  766         if((s & 0xF00) != 0x600)
  767                 return;
  768         if((s & 7) != 1){               /* not (device, no phy) */
  769                 iprint("ahci: slumbering drive unwakable %ux\n", s);
  770                 return;
  771         }
  772         p->sctl = 3*Aipm | 0*Aspd | Adet;
  773         delay(1);
  774         p->sctl &= ~7;
  775 //      iprint("ahci: wake %ux -> %ux\n", s, p->sstatus);
  776 }
  777 
  778 static int
  779 ahciconfigdrive(Ahba *h, Aportc *c, int mode)
  780 {
  781         Aportm *m;
  782         Aport *p;
  783 
  784         p = c->p;
  785         m = c->m;
  786 
  787         if(m->list == 0){
  788                 setupfis(&m->fis);
  789                 m->list = malign(sizeof *m->list, 1024);
  790                 m->ctab = malign(sizeof *m->ctab, 128);
  791         }
  792 
  793         if(p->sstatus & 3 && h->cap & Hsss){
  794                 /* device connected & staggered spin-up */
  795                 dprint("ahci: configdrive:  spinning up ... [%lux]\n",
  796                         p->sstatus);
  797                 p->cmd |= Apod|Asud;
  798                 asleep(1400);
  799         }
  800 
  801         p->serror = SerrAll;
  802 
  803         p->list = PCIWADDR(m->list);
  804         p->listhi = 0;
  805         p->fis = PCIWADDR(m->fis.base);
  806         p->fishi = 0;
  807         p->cmd |= Afre|Ast;
  808 
  809         if((p->sstatus & 0xF0F) == 0x601) /* drive coming up in slumbering? */
  810                 ahciwakeup(p);
  811 
  812         /* disable power managment sequence from book. */
  813         p->sctl = (3*Aipm) | (mode*Aspd) | 0*Adet;
  814         p->cmd &= ~Aalpe;
  815 
  816         p->ie = IEM;
  817 
  818         return 0;
  819 }
  820 
  821 static int
  822 ahcienable(Ahba *h)
  823 {
  824         h->ghc |= Hie;
  825         return 0;
  826 }
  827 
  828 static int
  829 ahcidisable(Ahba *h)
  830 {
  831         h->ghc &= ~Hie;
  832         return 0;
  833 }
  834 
  835 static int
  836 countbits(ulong u)
  837 {
  838         int i, n;
  839 
  840         n = 0;
  841         for(i = 0; i < 32; i++)
  842                 if(u & (1<<i))
  843                         n++;
  844         return n;
  845 }
  846 
  847 static int
  848 ahciconf(Ctlr *ctlr)
  849 {
  850         Ahba *h;
  851         ulong u;
  852 
  853         h = ctlr->hba = (Ahba*)ctlr->mmio;
  854         u = h->cap;
  855 
  856         if((u&Hsam) == 0)
  857                 h->ghc |= Hae;
  858 
  859         print("#S/sd%c: ahci %s port %#p: sss %ld ncs %ld coal %ld "
  860                 "mports %ld led %ld clo %ld ems %ld\n",
  861                 ctlr->sdev->idno, tname[ctlr->type], h,
  862                 (u>>27) & 1, (u>>8) & 0x1f, (u>>7) & 1, u & 0x1f, (u>>25) & 1,
  863                 (u>>24) & 1, (u>>6) & 1);
  864         return countbits(h->pi);
  865 }
  866 
  867 static int
  868 ahcihbareset(Ahba *h)
  869 {
  870         int wait;
  871 
  872         h->ghc |= 1;
  873         for(wait = 0; wait < 1000; wait += 100){
  874                 if(h->ghc == 0)
  875                         return 0;
  876                 delay(100);
  877         }
  878         return -1;
  879 }
  880 
  881 static void
  882 idmove(char *p, ushort *a, int n)
  883 {
  884         int i;
  885         char *op, *e;
  886 
  887         op = p;
  888         for(i = 0; i < n/2; i++){
  889                 *p++ = a[i] >> 8;
  890                 *p++ = a[i];
  891         }
  892         *p = 0;
  893         while(p > op && *--p == ' ')
  894                 *p = 0;
  895         e = p;
  896         p = op;
  897         while(*p == ' ')
  898                 p++;
  899         memmove(op, p, n - (e - p));
  900 }
  901 
  902 static int
  903 identify(Drive *d)
  904 {
  905         ushort *id;
  906         vlong osectors, s;
  907         uchar oserial[21];
  908         SDunit *u;
  909 
  910         id = d->info;
  911         s = ahciidentify(&d->portc, id);
  912         if(s == -1){
  913                 d->state = Derror;
  914                 return -1;
  915         }
  916         osectors = d->sectors;
  917         memmove(oserial, d->serial, sizeof d->serial);
  918 
  919         d->sectors = s;
  920         d->smartrs = 0;
  921 
  922         idmove(d->serial, id+10, 20);
  923         idmove(d->firmware, id+23, 8);
  924         idmove(d->model, id+27, 40);
  925 
  926         u = d->unit;
  927         memset(u->inquiry, 0, sizeof u->inquiry);
  928         u->inquiry[2] = 2;
  929         u->inquiry[3] = 2;
  930         u->inquiry[4] = sizeof u->inquiry - 4;
  931         memmove(u->inquiry+8, d->model, 40);
  932 
  933         if(osectors != s && memcmp(oserial, d->serial, sizeof oserial) != 0){
  934                 d->mediachange = 1;
  935                 u->sectors = 0;
  936         }
  937         return 0;
  938 }
  939 
  940 static void
  941 clearci(Aport *p)
  942 {
  943         if(p->cmd & Ast) {
  944                 p->cmd &= ~Ast;
  945                 p->cmd |=  Ast;
  946         }
  947 }
  948 
  949 static void
  950 updatedrive(Drive *d)
  951 {
  952         ulong cause, serr, s0, pr, ewake;
  953         char *name;
  954         Aport *p;
  955         static ulong last;
  956 
  957         pr = 1;
  958         ewake = 0;
  959         p = d->port;
  960         cause = p->isr;
  961         serr = p->serror;
  962         p->isr = cause;
  963         name = "??";
  964         if(d->unit && d->unit->name)
  965                 name = d->unit->name;
  966 
  967         if(p->ci == 0){
  968                 d->portm.flag |= Fdone;
  969                 wakeup(&d->portm);
  970                 pr = 0;
  971         }else if(cause & Adps)
  972                 pr = 0;
  973         if(cause & Ifatal){
  974                 ewake = 1;
  975                 dprint("ahci: updatedrive: fatal\n");
  976         }
  977         if(cause & Adhrs){
  978                 if(p->task & 33){
  979                         dprint("ahci: Adhrs cause %lux serr %lux task %lux\n",
  980                                 cause, serr, p->task);
  981                         d->portm.flag |= Ferror;
  982                         ewake = 1;
  983                 }
  984                 pr = 0;
  985         }
  986         if(p->task & 1 && last != cause)
  987                 dprint("%s: err ca %lux serr %lux task %lux sstat %lux\n",
  988                         name, cause, serr, p->task, p->sstatus);
  989         if(pr)
  990                 dprint("%s: upd %lux ta %lux\n", name, cause, p->task);
  991 
  992         if(cause & (Aprcs|Aifs)){
  993                 s0 = d->state;
  994                 switch(p->sstatus & 7){
  995                 case 0:                         /* no device */
  996                         d->state = Dmissing;
  997                         break;
  998                 case 1:                         /* device but no phy comm. */
  999                         if((p->sstatus & 0xF00) == 0x600)
 1000                                 d->state = Dnew; /* slumbering */
 1001                         else
 1002                                 d->state = Derror;
 1003                         break;
 1004                 case 3:                         /* device & phy comm. estab. */
 1005                         /* power mgnt crap for suprise removal */
 1006                         p->ie |= Aprcs|Apcs;    /* is this required? */
 1007                         d->state = Dreset;
 1008                         break;
 1009                 case 4:                         /* phy off-line */
 1010                         d->state = Doffline;
 1011                         break;
 1012                 }
 1013                 dprint("%s: %s → %s [Apcrs] %lux\n", name,
 1014                         diskstates[s0], diskstates[d->state], p->sstatus);
 1015                 /* print pulled message here. */
 1016                 if(s0 == Dready && d->state != Dready)
 1017                         idprint("%s: pulled\n", name);
 1018                 if(d->state != Dready)
 1019                         d->portm.flag |= Ferror;
 1020                 ewake = 1;
 1021         }
 1022         p->serror = serr;
 1023         if(ewake){
 1024                 clearci(p);
 1025                 wakeup(&d->portm);
 1026         }
 1027         last = cause;
 1028 }
 1029 
 1030 static void
 1031 pstatus(Drive *d, ulong s)
 1032 {
 1033         /*
 1034          * bogus code because the first interrupt is currently dropped.
 1035          * likely my fault.  serror is maybe cleared at the wrong time.
 1036          */
 1037         switch(s){
 1038         case 0:                 /* no device */
 1039                 d->state = Dmissing;
 1040                 break;
 1041         case 1:                 /* device but no phy. comm. */
 1042                 break;
 1043         case 2:                 /* should this be missing?  need testcase. */
 1044                 dprint("ahci: pstatus 2\n");
 1045                 /* fallthrough */
 1046         case 3:                 /* device & phy. comm. */
 1047                 d->wait = 0;
 1048                 d->state = Dnew;
 1049                 break;
 1050         case 4:                 /* offline */
 1051                 d->state = Doffline;
 1052                 break;
 1053         case 6:                 /* ? not sure this makes sense. TODO */
 1054                 d->state = Dnew;
 1055                 break;
 1056         }
 1057 }
 1058 
 1059 static int
 1060 configdrive(Drive *d)
 1061 {
 1062         if(ahciconfigdrive(d->ctlr->hba, &d->portc, d->mode) == -1)
 1063                 return -1;
 1064         ilock(d);
 1065         pstatus(d, d->port->sstatus & 7);
 1066         iunlock(d);
 1067         return 0;
 1068 }
 1069 
 1070 static void
 1071 resetdisk(Drive *d)
 1072 {
 1073         uint state, det, stat;
 1074         Aport *p;
 1075 
 1076         p = d->port;
 1077         det = p->sctl & 7;
 1078         stat = p->sstatus & 7;
 1079         state = (p->cmd>>28) & 0xf;
 1080         dprint("ahci: resetdisk: icc %ux  det %d sdet %d\n", state, det, stat);
 1081 
 1082         ilock(d);
 1083         state = d->state;
 1084         if(d->state != Dready || d->state != Dnew)
 1085                 d->portm.flag |= Ferror;
 1086         clearci(p);                     /* satisfy sleep condition. */
 1087         wakeup(&d->portm);
 1088         if(stat != 3){          /* device absent or phy not communicating? */
 1089                 d->state = Dportreset;
 1090                 iunlock(d);
 1091                 return;
 1092         }
 1093         d->state = Derror;
 1094         iunlock(d);
 1095 
 1096         qlock(&d->portm);
 1097         if(p->cmd&Ast && ahciswreset(&d->portc) == -1){
 1098                 ilock(d);
 1099                 d->state = Dportreset;  /* get a bigger stick. */
 1100                 iunlock(d);
 1101         } else {
 1102                 ilock(d);
 1103                 d->state = Dmissing;
 1104                 iunlock(d);
 1105 
 1106                 configdrive(d);
 1107         }
 1108         dprint("ahci: resetdisk: %s → %s\n",
 1109                 diskstates[state], diskstates[d->state]);
 1110         qunlock(&d->portm);
 1111 }
 1112 
 1113 static int
 1114 newdrive(Drive *d)
 1115 {
 1116         char *name, *s;
 1117         Aportc *c;
 1118         Aportm *m;
 1119 
 1120         c = &d->portc;
 1121         m = &d->portm;
 1122 
 1123         name = d->unit->name;
 1124         if(name == 0)
 1125                 name = "??";
 1126 
 1127         if(d->port->task == 0x80)
 1128                 return -1;
 1129         qlock(c->m);
 1130         if(setudmamode(c, 5) == -1){
 1131                 dprint("%s: can't set udma mode\n", name);
 1132                 goto lose;
 1133         }
 1134         if(identify(d) == -1){
 1135                 dprint("%s: identify failure\n", name);
 1136                 goto lose;
 1137         }
 1138         if(m->feat & Dpower && setfeatures(c, 0x85) == -1){
 1139                 m->feat &= ~Dpower;
 1140                 if(ahcirecover(c) == -1)
 1141                         goto lose;
 1142         }
 1143 
 1144         ilock(d);
 1145         d->state = Dready;
 1146         iunlock(d);
 1147 
 1148         qunlock(c->m);
 1149 
 1150         s = "";
 1151         if(m->feat & Dllba)
 1152                 s = "L";
 1153         idprint("%s: %sLBA %,lld sectors\n", d->unit->name, s, d->sectors);
 1154         idprint("  %s %s %s %s\n", d->model, d->firmware, d->serial,
 1155                 d->mediachange? "[mediachange]": "");
 1156         return 0;
 1157 
 1158 lose:
 1159         idprint("%s: can't be initialized\n", d->unit->name);
 1160         ilock(d);
 1161         d->state = Dnull;
 1162         iunlock(d);
 1163         qunlock(c->m);
 1164         return -1;
 1165 }
 1166 
 1167 enum {
 1168         Nms             = 256,
 1169         Mphywait        =  2*1024/Nms - 1,
 1170         Midwait         = 16*1024/Nms - 1,
 1171         Mcomrwait       = 64*1024/Nms - 1,
 1172 };
 1173 
 1174 static void
 1175 westerndigitalhung(Drive *d)
 1176 {
 1177         if((d->portm.feat&Datapi) == 0 && d->active &&
 1178             TK2MS(MACHP(0)->ticks - d->intick) > 5000){
 1179                 dprint("%s: drive hung; resetting [%lux] ci %lx\n",
 1180                         d->unit->name, d->port->task, d->port->ci);
 1181                 d->state = Dreset;
 1182         }
 1183 }
 1184 
 1185 static ushort olds[NCtlr*NCtlrdrv];
 1186 
 1187 static int
 1188 doportreset(Drive *d)
 1189 {
 1190         int i;
 1191 
 1192         i = -1;
 1193         qlock(&d->portm);
 1194         if(ahciportreset(&d->portc) == -1)
 1195                 dprint("ahci: doportreset: fails\n");
 1196         else
 1197                 i = 0;
 1198         qunlock(&d->portm);
 1199         dprint("ahci: doportreset: portreset → %s  [task %lux]\n",
 1200                 diskstates[d->state], d->port->task);
 1201         return i;
 1202 }
 1203 
 1204 /* drive must be locked */
 1205 static void
 1206 statechange(Drive *d)
 1207 {
 1208         switch(d->state){
 1209         case Dnull:
 1210         case Doffline:
 1211                 if(d->unit->sectors != 0){
 1212                         d->sectors = 0;
 1213                         d->mediachange = 1;
 1214                 }
 1215                 /* fallthrough */
 1216         case Dready:
 1217                 d->wait = 0;
 1218                 break;
 1219         }
 1220 }
 1221 
 1222 static void
 1223 checkdrive(Drive *d, int i)
 1224 {
 1225         ushort s;
 1226         char *name;
 1227 
 1228         ilock(d);
 1229         name = d->unit->name;
 1230         s = d->port->sstatus;
 1231         if(s)
 1232                 d->lastseen = MACHP(0)->ticks;
 1233         if(s != olds[i]){
 1234                 dprint("%s: status: %04ux -> %04ux: %s\n",
 1235                         name, olds[i], s, diskstates[d->state]);
 1236                 olds[i] = s;
 1237                 d->wait = 0;
 1238         }
 1239         westerndigitalhung(d);
 1240         switch(d->state){
 1241         case Dnull:
 1242         case Dready:
 1243                 break;
 1244         case Dmissing:
 1245         case Dnew:
 1246                 switch(s & 0x107){
 1247                 case 1:         /* no device (pm), device but no phy. comm. */
 1248                         ahciwakeup(d->port);
 1249                         /* fall through */
 1250                 case 0:         /* no device */
 1251                         break;
 1252                 default:
 1253                         dprint("%s: unknown status %04ux\n", name, s);
 1254                         /* fall through */
 1255                 case 0x100:             /* active, no device */
 1256                         if(++d->wait&Mphywait)
 1257                                 break;
 1258 reset:
 1259                         if(++d->mode > DMsataii)
 1260                                 d->mode = 0;
 1261                         if(d->mode == DMsatai){ /* we tried everything */
 1262                                 d->state = Dportreset;
 1263                                 goto portreset;
 1264                         }
 1265                         dprint("%s: reset; new mode %s\n", name,
 1266                                 modename[d->mode]);
 1267                         iunlock(d);
 1268                         resetdisk(d);
 1269                         ilock(d);
 1270                         break;
 1271                 case 0x103:             /* active, device, phy. comm. */
 1272                         if((++d->wait&Midwait) == 0){
 1273                                 dprint("%s: slow reset %04ux task=%lux; %d\n",
 1274                                         name, s, d->port->task, d->wait);
 1275                                 goto reset;
 1276                         }
 1277                         s = (uchar)d->port->task;
 1278                         if(s == 0x7f || ((d->port->sig >> 16) != 0xeb14 &&
 1279                             (s & ~0x17) != (1<<6)))
 1280                                 break;
 1281                         iunlock(d);
 1282                         newdrive(d);
 1283                         ilock(d);
 1284                         break;
 1285                 }
 1286                 break;
 1287         case Doffline:
 1288                 if(d->wait++ & Mcomrwait)
 1289                         break;
 1290                 /* fallthrough */
 1291         case Derror:
 1292         case Dreset:
 1293                 dprint("%s: reset [%s]: mode %d; status %04ux\n",
 1294                         name, diskstates[d->state], d->mode, s);
 1295                 iunlock(d);
 1296                 resetdisk(d);
 1297                 ilock(d);
 1298                 break;
 1299         case Dportreset:
 1300 portreset:
 1301                 if(d->wait++ & 0xff && (s & 0x100) == 0)
 1302                         break;
 1303                 /* device is active */
 1304                 dprint("%s: portreset [%s]: mode %d; status %04ux\n",
 1305                         name, diskstates[d->state], d->mode, s);
 1306                 d->portm.flag |= Ferror;
 1307                 clearci(d->port);
 1308                 wakeup(&d->portm);
 1309                 if((s & 7) == 0){       /* no device */
 1310                         d->state = Dmissing;
 1311                         break;
 1312                 }
 1313                 iunlock(d);
 1314                 doportreset(d);
 1315                 ilock(d);
 1316                 break;
 1317         }
 1318         statechange(d);
 1319         iunlock(d);
 1320 }
 1321 
 1322 static void
 1323 satakproc(void*)
 1324 {
 1325         int i;
 1326 
 1327         for(;;){
 1328                 tsleep(&up->sleep, return0, 0, Nms);
 1329                 for(i = 0; i < niadrive; i++)
 1330                         checkdrive(iadrive[i], i);
 1331         }
 1332 }
 1333 
 1334 static void
 1335 iainterrupt(Ureg*, void *a)
 1336 {
 1337         int i;
 1338         ulong cause, m;
 1339         Ctlr *c;
 1340         Drive *d;
 1341 
 1342         c = a;
 1343         ilock(c);
 1344         cause = c->hba->isr;
 1345         for(i = 0; i < c->mport; i++){
 1346                 m = 1 << i;
 1347                 if((cause & m) == 0)
 1348                         continue;
 1349                 d = c->rawdrive + i;
 1350                 ilock(d);
 1351                 if(d->port->isr && c->hba->pi & m)
 1352                         updatedrive(d);
 1353                 c->hba->isr = m;
 1354                 iunlock(d);
 1355         }
 1356         iunlock(c);
 1357 }
 1358 
 1359 static int
 1360 iaverify(SDunit *u)
 1361 {
 1362         Ctlr *c;
 1363         Drive *d;
 1364 
 1365         c = u->dev->ctlr;
 1366         d = c->drive[u->subno];
 1367         ilock(c);
 1368         ilock(d);
 1369         d->unit = u;
 1370         iunlock(d);
 1371         iunlock(c);
 1372         checkdrive(d, d->driveno);              /* c->d0 + d->driveno */
 1373         return 1;
 1374 }
 1375 
 1376 static int
 1377 iaenable(SDev *s)
 1378 {
 1379         char name[32];
 1380         Ctlr *c;
 1381         static int once;
 1382 
 1383         c = s->ctlr;
 1384         ilock(c);
 1385         if(!c->enabled) {
 1386                 if(once == 0) {
 1387                         once = 1;
 1388                         kproc("iasata", satakproc, 0);
 1389                 }
 1390                 if(c->ndrive == 0)
 1391                         panic("iaenable: zero s->ctlr->ndrive");
 1392                 pcisetbme(c->pci);
 1393                 snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
 1394                 intrenable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
 1395                 /* supposed to squelch leftover interrupts here. */
 1396                 ahcienable(c->hba);
 1397                 c->enabled = 1;
 1398         }
 1399         iunlock(c);
 1400         return 1;
 1401 }
 1402 
 1403 static int
 1404 iadisable(SDev *s)
 1405 {
 1406         char name[32];
 1407         Ctlr *c;
 1408 
 1409         c = s->ctlr;
 1410         ilock(c);
 1411         ahcidisable(c->hba);
 1412         snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
 1413         intrdisable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
 1414         c->enabled = 0;
 1415         iunlock(c);
 1416         return 1;
 1417 }
 1418 
 1419 static int
 1420 iaonline(SDunit *unit)
 1421 {
 1422         int r;
 1423         Ctlr *c;
 1424         Drive *d;
 1425 
 1426         c = unit->dev->ctlr;
 1427         d = c->drive[unit->subno];
 1428         r = 0;
 1429 
 1430         if(d->portm.feat & Datapi && d->mediachange){
 1431                 r = scsionline(unit);
 1432                 if(r > 0)
 1433                         d->mediachange = 0;
 1434                 return r;
 1435         }
 1436 
 1437         ilock(d);
 1438         if(d->mediachange){
 1439                 r = 2;
 1440                 d->mediachange = 0;
 1441                 /* devsd resets this after online is called; why? */
 1442                 unit->sectors = d->sectors;
 1443                 unit->secsize = 512;
 1444         } else if(d->state == Dready)
 1445                 r = 1;
 1446         iunlock(d);
 1447         return r;
 1448 }
 1449 
 1450 /* returns locked list! */
 1451 static Alist*
 1452 ahcibuild(Aportm *m, uchar *cmd, void *data, int n, vlong lba)
 1453 {
 1454         uchar *c, acmd, dir, llba;
 1455         Alist *l;
 1456         Actab *t;
 1457         Aprdt *p;
 1458         static uchar tab[2][2] = { 0xc8, 0x25, 0xca, 0x35, };
 1459 
 1460         dir = *cmd != 0x28;
 1461         llba = m->feat&Dllba? 1: 0;
 1462         acmd = tab[dir][llba];
 1463         qlock(m);
 1464         l = m->list;
 1465         t = m->ctab;
 1466         c = t->cfis;
 1467 
 1468         c[0] = 0x27;
 1469         c[1] = 0x80;
 1470         c[2] = acmd;
 1471         c[3] = 0;
 1472 
 1473         c[4] = lba;             /* sector               lba low 7:0 */
 1474         c[5] = lba >> 8;        /* cylinder low         lba mid 15:8 */
 1475         c[6] = lba >> 16;       /* cylinder hi          lba hi  23:16 */
 1476         c[7] = 0xa0 | 0x40;     /* obsolete device bits + lba */
 1477         if(llba == 0)
 1478                 c[7] |= (lba>>24) & 7;
 1479 
 1480         c[8] = lba >> 24;       /* sector (exp)         lba     31:24 */
 1481         c[9] = lba >> 32;       /* cylinder low (exp)   lba     39:32 */
 1482         c[10] = lba >> 48;      /* cylinder hi (exp)    lba     48:40 */
 1483         c[11] = 0;              /* features (exp); */
 1484 
 1485         c[12] = n;              /* sector count */
 1486         c[13] = n >> 8;         /* sector count (exp) */
 1487         c[14] = 0;              /* r */
 1488         c[15] = 0;              /* control */
 1489 
 1490         *(ulong*)(c + 16) = 0;
 1491 
 1492         l->flags = 1<<16 | Lpref | 0x5; /* Lpref ?? */
 1493         if(dir == Write)
 1494                 l->flags |= Lwrite;
 1495         l->len = 0;
 1496         l->ctab = PCIWADDR(t);
 1497         l->ctabhi = 0;
 1498 
 1499         p = &t->prdt;
 1500         p->dba = PCIWADDR(data);
 1501         p->dbahi = 0;
 1502         p->count = 1<<31 | (512*n - 2) | 1;
 1503 
 1504         return l;
 1505 }
 1506 
 1507 static Alist*
 1508 ahcibuildpkt(Aportm *m, SDreq *r, void *data, int n)
 1509 {
 1510         int fill, len;
 1511         uchar *c;
 1512         Alist *l;
 1513         Actab *t;
 1514         Aprdt *p;
 1515 
 1516         qlock(m);
 1517         l = m->list;
 1518         t = m->ctab;
 1519         c = t->cfis;
 1520 
 1521         fill = m->feat&Datapi16? 16: 12;
 1522         if((len = r->clen) > fill)
 1523                 len = fill;
 1524         memmove(t->atapi, r->cmd, len);
 1525         memset(t->atapi+len, 0, fill-len);
 1526 
 1527         c[0] = 0x27;
 1528         c[1] = 0x80;
 1529         c[2] = 0xa0;
 1530         if(n != 0)
 1531                 c[3] = 1;       /* dma */
 1532         else
 1533                 c[3] = 0;       /* features (exp); */
 1534 
 1535         c[4] = 0;               /* sector               lba low 7:0 */
 1536         c[5] = n;               /* cylinder low         lba mid 15:8 */
 1537         c[6] = n >> 8;          /* cylinder hi          lba hi  23:16 */
 1538         c[7] = 0xa0;            /* obsolete device bits */
 1539 
 1540         *(ulong*)(c + 8) = 0;
 1541         *(ulong*)(c + 12) = 0;
 1542         *(ulong*)(c + 16) = 0;
 1543 
 1544         l->flags = 1<<16 | Lpref | Latapi | 0x5;
 1545         if(r->write != 0 && data)
 1546                 l->flags |= Lwrite;
 1547         l->len = 0;
 1548         l->ctab = PCIWADDR(t);
 1549         l->ctabhi = 0;
 1550 
 1551         if(data == 0)
 1552                 return l;
 1553 
 1554         p = &t->prdt;
 1555         p->dba = PCIWADDR(data);
 1556         p->dbahi = 0;
 1557         p->count = 1<<31 | (n - 2) | 1;
 1558 
 1559         return l;
 1560 }
 1561 
 1562 static int
 1563 waitready(Drive *d)
 1564 {
 1565         ulong s, i, δ;
 1566 
 1567         for(i = 0; i < 15000; i += 250){
 1568                 if(d->state == Dreset || d->state == Dportreset ||
 1569                     d->state == Dnew)
 1570                         return 1;
 1571                 δ = MACHP(0)->ticks - d->lastseen;
 1572                 if(d->state == Dnull || δ > 10*1000)
 1573                         return -1;
 1574                 ilock(d);
 1575                 s = d->port->sstatus;
 1576                 iunlock(d);
 1577                 if((s & 0x700) == 0 && δ > 1500)
 1578                         return -1;      /* no detect */
 1579                 if(d->state == Dready && (s & 7) == 3)
 1580                         return 0;       /* ready, present & phy. comm. */
 1581                 esleep(250);
 1582         }
 1583         print("%s: not responding; offline\n", d->unit->name);
 1584         ilock(d);
 1585         d->state = Doffline;
 1586         iunlock(d);
 1587         return -1;
 1588 }
 1589 
 1590 static int
 1591 lockready(Drive *d)
 1592 {
 1593         int i;
 1594 
 1595         qlock(&d->portm);
 1596         while ((i = waitready(d)) == 1) {
 1597                 qunlock(&d->portm);
 1598                 esleep(1);
 1599                 qlock(&d->portm);
 1600         }
 1601         return i;
 1602 }
 1603 
 1604 static int
 1605 flushcache(Drive *d)
 1606 {
 1607         int i;
 1608 
 1609         i = -1;
 1610         if(lockready(d) == 0)
 1611                 i = ahciflushcache(&d->portc);
 1612         qunlock(&d->portm);
 1613         return i;
 1614 }
 1615 
 1616 static int
 1617 iariopkt(SDreq *r, Drive *d)
 1618 {
 1619         int n, count, try, max, flag, task;
 1620         char *name;
 1621         uchar *cmd, *data;
 1622         Aport *p;
 1623         Asleep as;
 1624 
 1625         cmd = r->cmd;
 1626         name = d->unit->name;
 1627         p = d->port;
 1628 
 1629         aprint("ahci: iariopkt: %02ux %02ux %c %d %p\n",
 1630                 cmd[0], cmd[2], "rw"[r->write], r->dlen, r->data);
 1631         if(cmd[0] == 0x5a && (cmd[2] & 0x3f) == 0x3f)
 1632                 return sdmodesense(r, cmd, d->info, sizeof d->info);
 1633         r->rlen = 0;
 1634         count = r->dlen;
 1635         max = 65536;
 1636 
 1637         try = 0;
 1638 retry:
 1639         data = r->data;
 1640         n = count;
 1641         if(n > max)
 1642                 n = max;
 1643         ahcibuildpkt(&d->portm, r, data, n);
 1644         switch(waitready(d)){
 1645         case -1:
 1646                 qunlock(&d->portm);
 1647                 return SDeio;
 1648         case 1:
 1649                 qunlock(&d->portm);
 1650                 esleep(1);
 1651                 goto retry;
 1652         }
 1653 
 1654         ilock(d);
 1655         d->portm.flag = 0;
 1656         iunlock(d);
 1657         p->ci = 1;
 1658 
 1659         as.p = p;
 1660         as.i = 1;
 1661         d->intick = MACHP(0)->ticks;
 1662         d->active++;
 1663 
 1664         while(waserror())
 1665                 ;
 1666         sleep(&d->portm, ahciclear, &as);
 1667         poperror();
 1668 
 1669         d->active--;
 1670         ilock(d);
 1671         flag = d->portm.flag;
 1672         task = d->port->task;
 1673         iunlock(d);
 1674 
 1675         if(task & (Efatal<<8) || task & (ASbsy|ASdrq) && d->state == Dready){
 1676                 d->port->ci = 0;
 1677                 ahcirecover(&d->portc);
 1678                 task = d->port->task;
 1679                 flag &= ~Fdone;         /* either an error or do-over */
 1680         }
 1681         qunlock(&d->portm);
 1682         if(flag == 0){
 1683                 if(++try == 10){
 1684                         print("%s: bad disk\n", name);
 1685                         r->status = SDcheck;
 1686                         return SDcheck;
 1687                 }
 1688                 print("%s: retry\n", name);
 1689                 goto retry;
 1690         }
 1691         if(flag & Ferror){
 1692                 if((task&Eidnf) == 0)
 1693                         print("%s: i/o error %ux\n", name, task);
 1694                 r->status = SDcheck;
 1695                 return SDcheck;
 1696         }
 1697 
 1698         data += n;
 1699 
 1700         r->rlen = data - (uchar*)r->data;
 1701         r->status = SDok;
 1702         return SDok;
 1703 }
 1704 
 1705 static int
 1706 iario(SDreq *r)
 1707 {
 1708         int i, n, count, try, max, flag, task;
 1709         vlong lba;
 1710         char *name;
 1711         uchar *cmd, *data;
 1712         Aport *p;
 1713         Asleep as;
 1714         Ctlr *c;
 1715         Drive *d;
 1716         SDunit *unit;
 1717 
 1718         unit = r->unit;
 1719         c = unit->dev->ctlr;
 1720         d = c->drive[unit->subno];
 1721         if(d->portm.feat & Datapi)
 1722                 return iariopkt(r, d);
 1723         cmd = r->cmd;
 1724         name = d->unit->name;
 1725         p = d->port;
 1726 
 1727         if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
 1728                 if(flushcache(d) == 0)
 1729                         return sdsetsense(r, SDok, 0, 0, 0);
 1730                 return sdsetsense(r, SDcheck, 3, 0xc, 2);
 1731         }
 1732 
 1733         if((i = sdfakescsi(r, d->info, sizeof d->info)) != SDnostatus){
 1734                 r->status = i;
 1735                 return i;
 1736         }
 1737 
 1738         if(*cmd != 0x28 && *cmd != 0x2a){
 1739                 print("%s: bad cmd 0x%.2ux\n", name, cmd[0]);
 1740                 r->status = SDcheck;
 1741                 return SDcheck;
 1742         }
 1743 
 1744         lba   = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5];
 1745         count = cmd[7]<<8 | cmd[8];
 1746         if(r->data == nil)
 1747                 return SDok;
 1748         if(r->dlen < count * unit->secsize)
 1749                 count = r->dlen / unit->secsize;
 1750         max = 128;
 1751 
 1752         try = 0;
 1753 retry:
 1754         data = r->data;
 1755         while(count > 0){
 1756                 n = count;
 1757                 if(n > max)
 1758                         n = max;
 1759                 ahcibuild(&d->portm, cmd, data, n, lba);
 1760                 switch(waitready(d)){
 1761                 case -1:
 1762                         qunlock(&d->portm);
 1763                         return SDeio;
 1764                 case 1:
 1765                         qunlock(&d->portm);
 1766                         esleep(1);
 1767                         goto retry;
 1768                 }
 1769                 ilock(d);
 1770                 d->portm.flag = 0;
 1771                 iunlock(d);
 1772                 p->ci = 1;
 1773 
 1774                 as.p = p;
 1775                 as.i = 1;
 1776                 d->intick = MACHP(0)->ticks;
 1777                 d->active++;
 1778 
 1779                 while(waserror())
 1780                         ;
 1781                 sleep(&d->portm, ahciclear, &as);
 1782                 poperror();
 1783 
 1784                 d->active--;
 1785                 ilock(d);
 1786                 flag = d->portm.flag;
 1787                 task = d->port->task;
 1788                 iunlock(d);
 1789 
 1790                 if(task & (Efatal<<8) ||
 1791                     task & (ASbsy|ASdrq) && d->state == Dready){
 1792                         d->port->ci = 0;
 1793                         ahcirecover(&d->portc);
 1794                         task = d->port->task;
 1795                 }
 1796                 qunlock(&d->portm);
 1797                 if(flag == 0){
 1798                         if(++try == 10){
 1799                                 print("%s: bad disk\n", name);
 1800                                 r->status = SDeio;
 1801                                 return SDeio;
 1802                         }
 1803                         iprint("%s: retry %lld\n", name, lba);
 1804                         goto retry;
 1805                 }
 1806                 if(flag & Ferror){
 1807                         iprint("%s: i/o error %ux @%,lld\n", name, task, lba);
 1808                         r->status = SDeio;
 1809                         return SDeio;
 1810                 }
 1811 
 1812                 count -= n;
 1813                 lba   += n;
 1814                 data += n * unit->secsize;
 1815         }
 1816         r->rlen = data - (uchar*)r->data;
 1817         r->status = SDok;
 1818         return SDok;
 1819 }
 1820 
 1821 /*
 1822  * configure drives 0-5 as ahci sata  (c.f. errata)
 1823  */
 1824 static int
 1825 iaahcimode(Pcidev *p)
 1826 {
 1827         dprint("iaahcimode: %ux %ux %ux\n", pcicfgr8(p, 0x91), pcicfgr8(p, 92),
 1828                 pcicfgr8(p, 93));
 1829         pcicfgw16(p, 0x92, pcicfgr32(p, 0x92) | 0xf);   /* ports 0-3 */
 1830 //      pcicfgw8(p, 0x93, pcicfgr32(p, 9x93) | 3);      /* ports 4-5 */
 1831         return 0;
 1832 }
 1833 
 1834 static void
 1835 iasetupahci(Ctlr *c)
 1836 {
 1837         /* disable cmd block decoding. */
 1838         pcicfgw16(c->pci, 0x40, pcicfgr16(c->pci, 0x40) & ~(1<<15));
 1839         pcicfgw16(c->pci, 0x42, pcicfgr16(c->pci, 0x42) & ~(1<<15));
 1840 
 1841         c->lmmio[0x4/4] |= 1 << 31;     /* enable ahci mode (ghc register) */
 1842         c->lmmio[0xc/4] = (1 << 6) - 1; /* 5 ports. (supposedly ro pi reg.) */
 1843 
 1844         /* enable ahci mode; from ich9 datasheet */
 1845         pcicfgw16(c->pci, 0x90, 1<<6 | 1<<5);
 1846 }
 1847 
 1848 static int
 1849 didtype(Pcidev *p)
 1850 {
 1851         switch(p->vid){
 1852         case 0x8086:
 1853                 if((p->did & 0xfffc) == 0x2680)
 1854                         return Tesb;
 1855                 /* 0x27c4 is the intel 82801 in compatibility (not sata) mode */
 1856                 if ((p->did & 0xfeff) == 0x2829 ||              /* ich8 */
 1857                     (p->did & 0xfffe) == 0x2922 ||              /* ich9 */
 1858                     (p->did & 0xfffe) == 0x27c4 /* || p->did == 0x27c0 */) /* 82801g[bh]m? */
 1859                         return Tich;
 1860                 break;
 1861         case 0x1002:
 1862                 if(p->did == 0x4380)
 1863                         return Tsb600;
 1864                 break;
 1865         }
 1866         if(p->ccrb == Pcibcstore && p->ccru == 6 && p->ccrp == 1)
 1867                 return Tunk;
 1868         return -1;
 1869 }
 1870 
 1871 static SDev*
 1872 iapnp(void)
 1873 {
 1874         int i, n, nunit, type;
 1875         ulong io;
 1876         Ctlr *c;
 1877         Drive *d;
 1878         Pcidev *p;
 1879         SDev *head, *tail, *s;
 1880         static int done;
 1881 
 1882         if(done++)
 1883                 return nil;
 1884 
 1885         memset(olds, 0xff, sizeof olds);
 1886         p = nil;
 1887         head = tail = nil;
 1888 loop:
 1889         while((p = pcimatch(p, 0, 0)) != nil){
 1890                 type = didtype(p);
 1891                 if (type == -1 || p->mem[Abar].bar == 0)
 1892                         continue;
 1893                 if(niactlr == NCtlr){
 1894                         print("ahci: %spnp: too many controllers\n",
 1895                                 tname[type]);
 1896                         break;
 1897                 }
 1898                 c = iactlr + niactlr;
 1899                 s = sdevs  + niactlr;
 1900                 memset(c, 0, sizeof *c);
 1901                 memset(s, 0, sizeof *s);
 1902                 io = p->mem[Abar].bar & ~0xf;
 1903                 c->mmio = vmap(io, p->mem[Abar].size);
 1904                 if(c->mmio == 0){
 1905                         print("ahci: %s: address 0x%luX in use did=%x\n",
 1906                                 Tname(c), io, p->did);
 1907                         continue;
 1908                 }
 1909                 c->lmmio = (ulong*)c->mmio;
 1910                 c->pci = p;
 1911                 c->type = type;
 1912 
 1913                 s->ifc = &sdiahciifc;
 1914                 s->idno = 'E' + niactlr;
 1915                 s->ctlr = c;
 1916                 c->sdev = s;
 1917 
 1918                 if(Intel(c) && p->did != 0x2681)
 1919                         iasetupahci(c);
 1920                 nunit = ahciconf(c);
 1921 //              ahcihbareset((Ahba*)c->mmio);
 1922                 if(Intel(c) && iaahcimode(p) == -1)
 1923                         break;
 1924                 if(nunit < 1){
 1925                         vunmap(c->mmio, p->mem[Abar].size);
 1926                         continue;
 1927                 }
 1928                 c->ndrive = s->nunit = nunit;
 1929                 c->mport = c->hba->cap & ((1<<5)-1);
 1930 
 1931                 i = (c->hba->cap >> 21) & 1;
 1932                 print("#S/sd%c: %s: sata-%s with %d ports\n", s->idno,
 1933                         Tname(c), "I\0II" + i*2, nunit);
 1934 
 1935                 /* map the drives -- they don't all need to be enabled. */
 1936                 memset(c->rawdrive, 0, sizeof c->rawdrive);
 1937                 n = 0;
 1938                 for(i = 0; i < NCtlrdrv; i++) {
 1939                         d = c->rawdrive + i;
 1940                         d->portno = i;
 1941                         d->driveno = -1;
 1942                         d->sectors = 0;
 1943                         d->serial[0] = ' ';
 1944                         d->ctlr = c;
 1945                         if((c->hba->pi & (1<<i)) == 0)
 1946                                 continue;
 1947                         d->port = (Aport*)(c->mmio + 0x80*i + 0x100);
 1948                         d->portc.p = d->port;
 1949                         d->portc.m = &d->portm;
 1950                         d->driveno = n++;
 1951                         c->drive[d->driveno] = d;
 1952                         iadrive[niadrive + d->driveno] = d;
 1953                 }
 1954                 for(i = 0; i < n; i++)
 1955                         if(ahciidle(c->drive[i]->port) == -1){
 1956                                 dprint("ahci: %s: port %d wedged; abort\n",
 1957                                         Tname(c), i);
 1958                                 goto loop;
 1959                         }
 1960                 for(i = 0; i < n; i++){
 1961                         c->drive[i]->mode = DMsatai;
 1962                         configdrive(c->drive[i]);
 1963                 }
 1964 
 1965                 niadrive += n;
 1966                 niactlr++;
 1967                 if(head)
 1968                         tail->next = s;
 1969                 else
 1970                         head = s;
 1971                 tail = s;
 1972         }
 1973         return head;
 1974 }
 1975 
 1976 static char* smarttab[] = {
 1977         "unset",
 1978         "error",
 1979         "threshold exceeded",
 1980         "normal"
 1981 };
 1982 
 1983 static char *
 1984 pflag(char *s, char *e, uchar f)
 1985 {
 1986         uchar i;
 1987 
 1988         for(i = 0; i < 8; i++)
 1989                 if(f & (1 << i))
 1990                         s = seprint(s, e, "%s ", flagname[i]);
 1991         return seprint(s, e, "\n");
 1992 }
 1993 
 1994 static int
 1995 iarctl(SDunit *u, char *p, int l)
 1996 {
 1997         char buf[32];
 1998         char *e, *op;
 1999         Aport *o;
 2000         Ctlr *c;
 2001         Drive *d;
 2002 
 2003         if((c = u->dev->ctlr) == nil)
 2004                 return 0;
 2005         d = c->drive[u->subno];
 2006         o = d->port;
 2007 
 2008         e = p+l;
 2009         op = p;
 2010         if(d->state == Dready){
 2011                 p = seprint(p, e, "model\t%s\n", d->model);
 2012                 p = seprint(p, e, "serial\t%s\n", d->serial);
 2013                 p = seprint(p, e, "firm\t%s\n", d->firmware);
 2014                 if(d->smartrs == 0xff)
 2015                         p = seprint(p, e, "smart\tenable error\n");
 2016                 else if(d->smartrs == 0)
 2017                         p = seprint(p, e, "smart\tdisabled\n");
 2018                 else
 2019                         p = seprint(p, e, "smart\t%s\n",
 2020                                 smarttab[d->portm.smart]);
 2021                 p = seprint(p, e, "flag\t");
 2022                 p = pflag(p, e, d->portm.feat);
 2023         }else
 2024                 p = seprint(p, e, "no disk present [%s]\n", diskstates[d->state]);
 2025         serrstr(o->serror, buf, buf + sizeof buf - 1);
 2026         p = seprint(p, e, "reg\ttask %lux cmd %lux serr %lux %s ci %lux is %lux; "
 2027                 "sig %lux sstatus %04lux\n", o->task, o->cmd, o->serror, buf,
 2028                 o->ci, o->isr, o->sig, o->sstatus);
 2029         p = seprint(p, e, "geometry %llud 512\n", d->sectors);
 2030         return p - op;
 2031 }
 2032 
 2033 static void
 2034 runflushcache(Drive *d)
 2035 {
 2036         long t0;
 2037 
 2038         t0 = MACHP(0)->ticks;
 2039         if(flushcache(d) != 0)
 2040                 error(Eio);
 2041         dprint("ahci: flush in %ld ms\n", MACHP(0)->ticks - t0);
 2042 }
 2043 
 2044 static void
 2045 forcemode(Drive *d, char *mode)
 2046 {
 2047         int i;
 2048 
 2049         for(i = 0; i < nelem(modename); i++)
 2050                 if(strcmp(mode, modename[i]) == 0)
 2051                         break;
 2052         if(i == nelem(modename))
 2053                 i = 0;
 2054         ilock(d);
 2055         d->mode = i;
 2056         iunlock(d);
 2057 }
 2058 
 2059 static void
 2060 runsmartable(Drive *d, int i)
 2061 {
 2062         if(waserror()){
 2063                 qunlock(&d->portm);
 2064                 d->smartrs = 0;
 2065                 nexterror();
 2066         }
 2067         if(lockready(d) == -1)
 2068                 error(Eio);
 2069         d->smartrs = smart(&d->portc, i);
 2070         d->portm.smart = 0;
 2071         qunlock(&d->portm);
 2072         poperror();
 2073 }
 2074 
 2075 static void
 2076 forcestate(Drive *d, char *state)
 2077 {
 2078         int i;
 2079 
 2080         for(i = 0; i < nelem(diskstates); i++)
 2081                 if(strcmp(state, diskstates[i]) == 0)
 2082                         break;
 2083         if(i == nelem(diskstates))
 2084                 error(Ebadctl);
 2085         ilock(d);
 2086         d->state = i;
 2087         iunlock(d);
 2088 }
 2089 
 2090 
 2091 static int
 2092 iawctl(SDunit *u, Cmdbuf *cmd)
 2093 {
 2094         char **f;
 2095         Ctlr *c;
 2096         Drive *d;
 2097         uint i;
 2098 
 2099         c = u->dev->ctlr;
 2100         d = c->drive[u->subno];
 2101         f = cmd->f;
 2102 
 2103         if(strcmp(f[0], "flushcache") == 0)
 2104                 runflushcache(d);
 2105         else if(strcmp(f[0], "identify") ==  0){
 2106                 i = strtoul(f[1]? f[1]: "", 0, 0);
 2107                 if(i > 0xff)
 2108                         i = 0;
 2109                 dprint("ahci: %04d %ux\n", i, d->info[i]);
 2110         }else if(strcmp(f[0], "mode") == 0)
 2111                 forcemode(d, f[1]? f[1]: "satai");
 2112         else if(strcmp(f[0], "nop") == 0){
 2113                 if((d->portm.feat & Dnop) == 0){
 2114                         cmderror(cmd, "no drive support");
 2115                         return -1;
 2116                 }
 2117                 if(waserror()){
 2118                         qunlock(&d->portm);
 2119                         nexterror();
 2120                 }
 2121                 if(lockready(d) == -1)
 2122                         error(Eio);
 2123                 nop(&d->portc);
 2124                 qunlock(&d->portm);
 2125                 poperror();
 2126         }else if(strcmp(f[0], "reset") == 0)
 2127                 forcestate(d, "reset");
 2128         else if(strcmp(f[0], "smart") == 0){
 2129                 if(d->smartrs == 0){
 2130                         cmderror(cmd, "smart not enabled");
 2131                         return -1;
 2132                 }
 2133                 if(waserror()){
 2134                         qunlock(&d->portm);
 2135                         d->smartrs = 0;
 2136                         nexterror();
 2137                 }
 2138                 if(lockready(d) == -1)
 2139                         error(Eio);
 2140                 d->portm.smart = 2 + smartrs(&d->portc);
 2141                 qunlock(&d->portm);
 2142                 poperror();
 2143         }else if(strcmp(f[0], "smartdisable") == 0)
 2144                 runsmartable(d, 1);
 2145         else if(strcmp(f[0], "smartenable") == 0)
 2146                 runsmartable(d, 0);
 2147         else if(strcmp(f[0], "state") == 0)
 2148                 forcestate(d, f[1]? f[1]: "null");
 2149         else{
 2150                 cmderror(cmd, Ebadctl);
 2151                 return -1;
 2152         }
 2153         return 0;
 2154 }
 2155 
 2156 static char *
 2157 portr(char *p, char *e, uint x)
 2158 {
 2159         int i, a;
 2160 
 2161         p[0] = 0;
 2162         a = -1;
 2163         for(i = 0; i < 32; i++){
 2164                 if((x & (1<<i)) == 0){
 2165                         if(a != -1 && i - 1 != a)
 2166                                 p = seprint(p, e, "-%d", i - 1);
 2167                         a = -1;
 2168                         continue;
 2169                 }
 2170                 if(a == -1){
 2171                         if(i > 0)
 2172                                 p = seprint(p, e, ", ");
 2173                         p = seprint(p, e, "%d", a = i);
 2174                 }
 2175         }
 2176         if(a != -1 && i - 1 != a)
 2177                 p = seprint(p, e, "-%d", i - 1);
 2178         return p;
 2179 }
 2180 
 2181 /* must emit exactly one line per controller (sd(3)) */
 2182 static char*
 2183 iartopctl(SDev *sdev, char *p, char *e)
 2184 {
 2185         ulong cap;
 2186         char pr[25];
 2187         Ahba *hba;
 2188         Ctlr *ctlr;
 2189 
 2190 #define has(x, str) if(cap & (x)) p = seprint(p, e, "%s ", (str))
 2191 
 2192         ctlr = sdev->ctlr;
 2193         hba = ctlr->hba;
 2194         p = seprint(p, e, "sd%c ahci port %#p: ", sdev->idno, hba);
 2195         cap = hba->cap;
 2196         has(Hs64a, "64a");
 2197         has(Hsalp, "alp");
 2198         has(Hsam, "am");
 2199         has(Hsclo, "clo");
 2200         has(Hcccs, "coal");
 2201         has(Hems, "ems");
 2202         has(Hsal, "led");
 2203         has(Hsmps, "mps");
 2204         has(Hsncq, "ncq");
 2205         has(Hssntf, "ntf");
 2206         has(Hspm, "pm");
 2207         has(Hpsc, "pslum");
 2208         has(Hssc, "slum");
 2209         has(Hsss, "ss");
 2210         has(Hsxs, "sxs");
 2211         portr(pr, pr + sizeof pr, hba->pi);
 2212         return seprint(p, e,
 2213                 "iss %ld ncs %ld np %ld; ghc %lux isr %lux pi %lux %s ver %lux\n",
 2214                 (cap>>20) & 0xf, (cap>>8) & 0x1f, 1 + (cap & 0x1f),
 2215                 hba->ghc, hba->isr, hba->pi, pr, hba->ver);
 2216 #undef has
 2217 }
 2218 
 2219 static int
 2220 iawtopctl(SDev *, Cmdbuf *cmd)
 2221 {
 2222         int *v;
 2223         char **f;
 2224 
 2225         f = cmd->f;
 2226         v = 0;
 2227 
 2228         if (f[0] == nil)
 2229                 return 0;
 2230         if(strcmp(f[0], "debug") == 0)
 2231                 v = &debug;
 2232         else if(strcmp(f[0], "idprint") == 0)
 2233                 v = &prid;
 2234         else if(strcmp(f[0], "aprint") == 0)
 2235                 v = &datapi;
 2236         else
 2237                 cmderror(cmd, Ebadctl);
 2238 
 2239         switch(cmd->nf){
 2240         default:
 2241                 cmderror(cmd, Ebadarg);
 2242         case 1:
 2243                 *v ^= 1;
 2244                 break;
 2245         case 2:
 2246                 if(f[1])
 2247                         *v = strcmp(f[1], "on") == 0;
 2248                 else
 2249                         *v ^= 1;
 2250                 break;
 2251         }
 2252         return 0;
 2253 }
 2254 
 2255 SDifc sdiahciifc = {
 2256         "iahci",
 2257 
 2258         iapnp,
 2259         nil,            /* legacy */
 2260         iaenable,
 2261         iadisable,
 2262 
 2263         iaverify,
 2264         iaonline,
 2265         iario,
 2266         iarctl,
 2267         iawctl,
 2268 
 2269         scsibio,
 2270         nil,            /* probe */
 2271         nil,            /* clear */
 2272         iartopctl,
 2273         iawtopctl,
 2274 };

Cache object: 2144a4fac0f94720ce1d0f361a592a64


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.