]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/sdodin.c
kernel: cleanup makefile for $CONF.$O target
[plan9front.git] / sys / src / 9 / pc / sdodin.c
1 /*
2  * marvell odin ii 88se64xx sata/sas controller
3  * copyright © 2009 erik quanstrom
4  * coraid, inc.
5  */
6
7 #include "u.h"
8 #include "../port/lib.h"
9 #include "mem.h"
10 #include "dat.h"
11 #include "fns.h"
12 #include "io.h"
13 #include "../port/error.h"
14 #include "../port/sd.h"
15 #include <fis.h>
16 #include "../port/led.h"
17
18 #define dprint(...)     if(debug)       print(__VA_ARGS__); else USED(debug)
19 #define idprint(...)    if(idebug)      print(__VA_ARGS__); else USED(idebug)
20 #define aprint(...)     if(adebug)      print(__VA_ARGS__); else USED(adebug)
21 #define Pciwaddrh(a)    0
22 #define Pciw64(x)       (uvlong)PCIWADDR(x)
23 #define Ticks           MACHP(0)->ticks
24
25 /* copied from sdiahci */
26 enum {
27         Dnull           = 0,
28         Dmissing                = 1<<0,
29         Dnopower        = 1<<1,
30         Dnew            = 1<<2,
31         Dready          = 1<<3,
32         Derror          = 1<<4,
33         Dreset          = 1<<5,
34         Doffline                = 1<<6,
35         Dportreset      = 1<<7,
36         Dlast           = 9,
37 };
38
39 static char *diskstates[Dlast] = {
40         "null",
41         "missing",
42         "nopower",
43         "new",
44         "ready",
45         "error",
46         "reset",
47         "offline",
48         "portreset",
49 };
50
51 static char *type[] = {
52         "offline",
53         "sas",
54         "sata",
55 };
56
57 enum{
58         Nctlr           = 4,
59         Nctlrdrv                = 8,
60         Ndrive          = Nctlr*Nctlrdrv,
61         Mbar            = 2,
62         Mebar           = 4,
63         Nqueue          = 32,           /* cmd queue size */
64         Qmask           = Nqueue - 1,
65         Nregset         = 8,
66         Rmask           = 0xffff,
67         Nms             = 256,          /* drive check rate */
68
69         Sas             = 1,
70         Sata,
71
72         /* cmd bits */
73         Error           = 1<<31,
74         Done            = 1<<30,
75         Noverdict       = 1<<29,
76         Creset          = 1<<28,
77         Atareset                = 1<<27,
78         Sense           = 1<<26,
79         Timeout         = 1<<25,
80         Response        = 1<<24,
81         Active          = 1<<23,
82
83         /* pci registers */
84         Phy0            = 0x40,
85         Gpio            = 0x44,
86         Phy1            = 0x90,
87         Gpio1           = 0x94,
88         Dctl            = 0xe8,
89
90         /* phy offests */
91         Phydisable      = 1<<12,
92         Phyrst          = 1<<16,
93         Phypdwn         = 1<<20,
94         Phyen           = 1<<24,
95
96         /* bar4 registers */
97         Gctl            = 0x004/4,
98         Gis             = 0x008/4,      /* global interrupt status */
99         Pi              = 0x00c/4,      /* ports implemented */
100         Flashctl                = 0x030/4,      /* spi flash control */
101         Flashcmd        = 0x034/4,      /* flash wormhole */
102         Flashdata       = 0x038/4,
103         I²cctl         = 0x040/4,      /* i²c control */
104         I²ccmd         = 0x044/4,
105         I²cdata                = 0x048/4,
106         Ptype           = 0x0a0/4,      /* 15:8 auto detect enable; 7:0 sas=1. sata=0 */
107         Portcfg0                = 0x100/4,      /* 31:16 register sets 31:16 */
108         Portcfg1                = 0x104/4,      /* 31:16 register sets 15:8 tx enable; 7 rx enable */
109         Clbase          = 0x108/4,      /* cmd list base; 64 bits */
110         Fisbase         = 0x110/4,      /* 64 bits */
111         Dqcfg           = 0x120/4,      /* bits 11:0 specify size */
112         Dqbase          = 0x124/4,
113         Dqwp            = 0x12c/4,      /* delivery queue write pointer */
114         Dqrp            = 0x130/4,
115         Cqcfg           = 0x134/4,
116         Cqbase          = 0x138/4,
117         Cqwp            = 0x140/4,      /* hw */
118         Coal            = 0x148/4,
119         Coalto          = 0x14c/4,      /* coal timeout µs */
120         Cis             = 0x150/4,      /* centeral irq status */
121         Cie             = 0x154/4,      /* centeral irq enable */
122         Csis            = 0x158/4,      /* cmd set irq status */
123         Csie            = 0x15c/4,
124         Cmda            = 0x1b8/4,
125         Cmdd            = 0x1bc/4,
126         Gpioa           = 0x270/4,
127         Gpiod           = 0x274/4,
128         Gpiooff         = 0x100,                /* second gpio offset */
129
130         /* port conf registers; mapped through wormhole */
131         Pinfo           = 0x000,
132         Paddr           = 0x004,
133         Painfo          = 0x00c,                /* attached device info */
134         Pawwn           = 0x010,
135         Psatactl                = 0x018,
136         Pphysts         = 0x01c,
137         Psig            = 0x020,                /* 16 bytes */
138         Perr            = 0x030,
139         Pcrcerr         = 0x034,
140         Pwidecfg                = 0x038,
141         Pwwn            = 0x080,                /* 12 wwn + ict */
142
143         /* port cmd registers; mapped through “cmd” wormhole */
144         Ci              = 0x040,                /* cmd active (16) */
145         Task            = 0x080,
146         Rassoc          = 0x0c0,
147         Pfifo0          = 0x1a8,
148         Pfifo1          = 0x1c4,
149         Pwdtimer        = 0x13c,
150
151         /* “vendor specific” wormhole */
152         Phymode = 0x001,
153
154         /* gpio wormhole */
155         Sgconf0         = 0x000,
156         Sgconf1         = 0x004,
157         Sgclk           = 0x008,
158         Sgconf3         = 0x00c,
159         Sgis            = 0x010,                /* interrupt set */
160         Sgie            = 0x014,                /* interrupt enable */
161         Drivesrc                = 0x020,                /* 4 drives/register; 4 bits/drive */
162         Drivectl                = 0x038,                /* same deal */
163
164         /* Gctl bits */
165         Reset           = 1<<0,
166         Intenable       = 1<<1,
167
168         /* Portcfg0/1 bits */
169         Regen           = 1<<16,        /* enable sata regsets 31:16 or 15:0 */
170         Xmten           = 1<<8, /* enable port n transmission */
171         Dataunke        = 1<<3,
172         Rsple           = 1<<2, /* response frames in le format */
173         Oabe            = 1<<1, /* oa frame in big endian format */
174         Framele         = 1<<0, /* frame contents in le format */
175
176         Allresrx                = 1<<7, /* receive all responses */
177         Stpretry                = 1<<6,
178         Cmdirq          = 1<<5, /* 1 == self clearing */
179         Fisen           = 1<<4, /* enable fis rx */
180         Errstop         = 1<<3, /* set -> stop on ssp/smp error */
181         Resetiss                = 1<<1, /* reset cmd issue; self clearing */
182         Issueen         = 1<<0,
183
184         /* Dqcfg bits */
185         Dqen            = 1<<16,
186
187         /* Cqcfg bits */
188         Noattn          = 1<<17,        /* don't post entries with attn bit */
189         Cqen            = 1<<16,
190
191         /* Cis bits */
192         I2cirq          = 1<<31,
193         Swirq1          = 1<<30,
194         Swirq0          = 1<<29,
195         Prderr          = 1<<28,
196         Dmato           = 1<<27,
197         Parity          = 1<<28,        /* parity error; fatal */
198         Slavei2c                = 1<<25,
199         Portstop                = 1<<16,        /* bitmapped */
200         Portirq         = 1<<8, /* bitmapped */
201         Srsirq          = 1<<3,
202         Issstop         = 1<<1,
203         Cdone           = 1<<0,
204         Iclr            = Swirq1 | Swirq0,
205
206         /* Pis bits */
207         Caf             = 1<<29,        /* clear affiliation fail */
208         Sync            = 1<<25,        /* sync during fis rx */
209         Phyerr          = 1<<24,
210         Stperr          = 1<<23,
211         Crcerr          = 1<<22,
212         Linktx          = 1<<21,
213         Linkrx          = 1<<20,
214         Martianfis      = 1<<19,
215         Anot            = 1<<18,        /* async notification */
216         Bist            = 1<<17,
217         Sigrx           = 1<<16,        /* native sata signature rx */
218         Phyunrdy        = 1<<12,        /* phy went offline*/
219         Uilong          = 1<<11,
220         Uishort         = 1<<10,
221         Martiantag      = 1<<9,
222         Bnot            = 1<<8, /* broadcast noticication */
223         Comw            = 1<<7,
224         Portsel         = 1<<6,
225         Hreset          = 1<<5,
226         Phyidto         = 1<<4,
227         Phyidfail               = 1<<3,
228         Phyidok         = 1<<2,
229         Hresetok                = 1<<1,
230         Phyrdy          = 1<<0,
231
232         Pisataup                = Phyrdy | Comw | Sigrx,
233         Pisasup         = Phyrdy | Comw | Phyidok,
234         Piburp          = Sync | Phyerr | Stperr | Crcerr | Linktx |
235                                 Linkrx | Martiantag,
236         Pireset         = Phyidfail | Bnot | Phyunrdy | Bist |
237                                 Anot | Martianfis | Bist | Phyidto |
238                                 Hreset,
239         Piunsupp        = Portsel,
240
241         /* Psc bits */
242         Sphyrdy         = 1<<20,
243         Linkrate                = 1<<18,        /* 4 bits */
244         Maxrate         = 1<<12,
245         Minrate         = 1<<8,
246         Sreset          = 1<<3,
247         Sbnote          = 1<<2,
248         Shreset         = 1<<1,
249         Sphyrst         = 1<<0,
250
251         /* Painfo bits */
252         Issp            = 1<<19,
253         Ismp            = 1<<18,
254         Istp            = 1<<17,
255         Itype           = 1<<0, /* two bits */
256
257         /* Psatactl bits */
258         Powerctl                = 1<<30,        /* 00 wake; 10 partial 01 slumb */
259         Srst            = 1<<29,        /* soft reset */
260         Power           = 1<<28,
261         Sportsel                = 1<<24,
262         Dmahon          = 1<<22,
263         Srsten          = 1<<20,
264         Dmaxfr          = 1<<18,
265
266         /* phy status bits */
267         Phylock         = 1<<9,
268         Nspeed          = 1<<4,
269         Psphyrdy                = 1<<2,
270
271         /* Task bits; modeled after ahci */
272         Eestatus                = 0xff<<24,
273         Asdbs           = 1<<18,
274         Apio            = 1<<17,
275         Adhrs           = 1<<16,
276         Eerror          = 0xff<<8,
277         Estatus         = 0xff,
278
279         /* Phymode bits */
280         Pmnotify                = 1<<24,
281         Pmnotifyen      = 1<<23,
282
283         /* Sgconf0 bits */
284         Autolen         = 1<<24,        /* 8 bits */
285         Manlen          = 1<<16,        /* 8 bits */
286         Sdincapt                = 1<<8, /* capture sdatain on + edge */
287         Sdoutch         = 1<<7, /* change sdataout on - edge
288         Sldch           = 1<<6, /* change sload on - edge
289         Sdoutivt                = 1<<5, /* invert sdataout polarity */
290         Ldivt           = 1<<4,
291         Sclkivt         = 1<<3,
292         Blinkben                = 1<<2, /* enable blink b */
293         Blinkaen                = 1<<1, /* enable blink a */
294         Sgpioen         = 1<<0,
295
296         /* Sgconf1 bits; 4 bits each */
297         Sactoff         = 1<<28,        /* stretch activity off; 0/64 - 15/64 */
298         Sacton          = 1<<24,        /* 1/64th - 16/64 */
299         Factoff         = 1<<20,        /* 0/8 - 15/8; default 1 */
300         Facton          = 1<<16,        /* 0/4 - 15/4; default 2 */
301         Bhi             = 1<<12,        /* 1/8 - 16/8 */
302         Blo             = 1<<8, /* 1/8 - 16/8 */
303         Ahi             = 1<<4, /* 1/8 - 16/8 */
304         Alo             = 1<<0, /* 1/8 - 16/8 */
305
306         /* Sgconf3 bits */
307         Autopat         = 1<<20,        /* 4 bits of start pattern */
308         Manpat          = 1<<16,
309         Manrep          = 1<<4, /* repeats; 7ff ≡ ∞ */
310         Sdouthalt       = 0<<2,
311         Sdoutman        = 1<<2,
312         Sdoutauto       = 2<<2,
313         Sdoutma         = 3<<2,
314         Sdincapoff      = 0<<0,
315         Sdinoneshot     = 1<<0,
316         Sdinrep         = 2<<0,
317
318         /* Sgie Sgis bits */
319         Sgreprem        = 1<<8, /* 12 bits; not irq related */
320         Manrep0         = 1<<1, /* write 1 to clear */
321         Capdone = 1<<0, /* capture done */
322
323         /* drive control bits (repeated 4x per drive) */
324         Aled            = 1<<5, /* 3 bits */
325         Locled          = 1<<3, /* 2 bits */
326         Errled          = 1<<0, /* 3 bits */
327         Llow            = 0,
328         Lhigh           = 1,
329         Lblinka         = 2,
330         Lblinkaneg      = 3,
331         Lsof            = 4,
332         Leof            = 5,
333         Lblinkb         = 6,
334         Lblinkbneg      = 7,
335
336         /* cmd queue bits */
337         Dssp            = 1<<29,
338         Dsmp            = 2<<29,
339         Dsata           = 3<<29,        /* also stp */
340         Ditor           = 1<<28,        /* initiator */
341         Dsatareg                = 1<<20,
342         Dphyno          = 1<<12,
343         Dcslot          = 1,
344
345         /* completion queue bits */
346         Cgood           = 1<<23,        /* ssp only */
347         Cresetdn                = 1<<21,
348         Crx             = 1<<20,        /* target mode */
349         Cattn           = 1<<19,
350         Crxfr           = 1<<18,
351         Cerr            = 1<<17,
352         Cqdone          = 1<<16,
353         Cslot           = 1<<0, /* 12 bits */
354
355         /* error bits — first word */
356         Eissuestp       = 1<<31,        /* cmd issue stopped */
357         Epi             = 1<<30,        /* protection info error */
358         Eoflow          = 1<<29,        /* buffer overflow */
359         Eretry          = 1<<28,        /* retry limit exceeded */
360         Eufis           = 1<<27,
361         Edmat           = 1<<26,        /* dma terminate */
362         Esync           = 1<<25,        /* sync rx during tx */
363         Etask           = 1<<24,
364         Ererr           = 1<<23,        /* r error received */
365
366         Eroff           = 1<<20,        /* read data offset error */
367         Exoff           = 1<<19,        /* xfer rdy offset error */
368         Euxr            = 1<<18,        /* unexpected xfer rdy */
369         Exflow          = 1<<16,        /* buffer over/underflow */
370         Elock           = 1<<15,        /* interlock error */
371         Enak            = 1<<14,
372         Enakto          = 1<<13,
373         Enoak           = 1<<12,        /* conn closed wo nak */
374         Eopento         = 1<<11,        /* open conn timeout */
375         Epath           = 1<<10,        /* open reject - path blocked */
376         Enodst          = 1<<9, /* open reject - no dest */
377         Estpbsy         = 1<<8, /* stp resource busy */
378         Ebreak          = 1<<7, /* break while sending */
379         Ebaddst         = 1<<6, /* open reject - bad dest */
380         Ebadprot        = 1<<5, /* open reject - proto not supp */
381         Erate           = 1<<4, /* open reject - rate not supp */
382         Ewdest          = 1<<3, /* open reject - wrong dest */
383         Ecreditto       = 1<<2, /* credit timeout */
384         Edog            = 1<<1, /* watchdog timeout */
385         Eparity         = 1<<0, /* buffer parity error */
386
387         /* sas ctl cmd header bits */
388         Ssptype         = 1<<5, /* 3 bits */
389         Ssppt           = 1<<4, /* build your own header *.
390         Firstburst      = 1<<3, /* first burst */
391         Vrfylen         = 1<<2, /* verify length */
392         Tlretry         = 1<<1, /* transport layer retry */
393         Piren           = 1<<0, /* pir present */
394
395         /* sata ctl cmd header bits */
396         Lreset          = 1<<7,
397         Lfpdma          = 1<<6, /* first-party dma.  (what's that?) */
398         Latapi          = 1<<5,
399         Lpm             = 1<<0, /* 4 bits */
400
401         Sspcmd          = 0*Ssptype,
402         Ssptask         = 1*Ssptype,
403         Sspxfrdy                = 4*Ssptype,
404         Ssprsp          = 5*Ssptype,
405         Sspread         = 6*Ssptype,
406         Sspwrite                = 7*Ssptype,
407 };
408
409 /* following ahci */
410 typedef struct {
411         ulong   dba;
412         ulong   dbahi;
413         ulong   pad;
414         ulong   count;
415 } Aprdt;
416
417 typedef struct {
418         union{
419                 struct{
420                         uchar   cfis[0x40];
421                         uchar   atapi[0x20];
422                 };
423                 struct{
424                         uchar   mfis[0x40];
425                 };
426                 struct{
427                         uchar   sspfh[0x18];
428                         uchar   sasiu[0x40];
429                 };
430         };
431 } Ctab;
432
433 /* protection information record */
434 typedef struct {
435         uchar   ctl;
436         uchar   pad;
437         uchar   size[2];
438         uchar   rtag[4];
439         uchar   atag[2];
440         uchar   mask[2];
441 } Pir;
442
443 /* open address frame */
444 typedef struct {
445         uchar   oaf[0x28];
446         uchar   fb[4];
447 } Oaf;
448
449 /* status buffer */
450 typedef struct {
451         uchar   error[8];
452         uchar   rsp[0x400];
453 } Statb;
454
455 typedef struct {
456         uchar   satactl;
457         uchar   sasctl;
458         uchar   len[2];
459
460         uchar   fislen[2];
461         uchar   maxrsp;
462         uchar   d0;
463
464         uchar   tag[2];
465         uchar   ttag[2];
466
467         uchar   dlen[4];
468         uchar   ctab[8];
469         uchar   oaf[8];
470         uchar   statb[8];
471         uchar   prd[8];
472
473         uchar   d3[16];
474 } Cmdh;
475
476 typedef struct Cmd Cmd;
477 struct Cmd {
478         Rendez;
479         uint    cflag;
480
481         Cmdh    *cmdh;
482         Ctab;
483         Oaf;
484         Statb;
485         Aprdt;
486 };
487
488 typedef struct Drive Drive;
489 typedef struct Ctlr Ctlr;
490
491 struct Drive {
492         Lock;
493         QLock;
494         Ctlr    *ctlr;
495         SDunit  *unit;
496         char    name[16];
497
498         Cmd     *cmd;
499
500         /* sdscsi doesn't differentiate drivechange/mediachange */
501         uchar   drivechange;
502         uchar   state;
503         uchar   type;
504         ushort  info[0x100];
505
506         Sfis;   /* sata and media info*/
507         Cfis;   /* sas and media info */
508         Ledport;        /* led */
509
510         /* hotplug info */
511         uint    lastseen;
512         uint    intick;
513         uint    wait;
514
515         char    serial[20+1];
516         char    firmware[8+1];
517         char    model[40+1];
518         uvlong  wwn;
519         uvlong  sectors;
520         uint    secsize;
521
522         uint    driveno;
523 };
524
525 struct Ctlr {
526         Lock;
527         uchar   enabled;
528         SDev    *sdev;
529         Pcidev  *pci;
530         uint    *reg;
531
532         uint    dq[Nqueue];
533         uint    dqwp;
534         uint    cq[Nqueue + 1];
535         uint    cqrp;
536         Cmdh    *cl;
537         uchar   *fis;
538         Cmd     *cmdtab;
539
540         Drive   drive[Nctlrdrv];
541         uint    ndrive;
542 };
543
544 static  Ctlr    msctlr[Nctlr];
545 static  SDev    sdevs[Nctlr];
546 static  uint    nmsctlr;
547 static  Drive   *msdrive[Ndrive];
548 static  uint    nmsdrive;
549 static  int     debug=0;
550 static  int     idebug=1;
551 static  int     adebug;
552 static  uint     olds[Nctlr*Nctlrdrv];
553         SDifc   sdodinifc;
554
555 /* a good register is hard to find */
556 static  int     pis[] = {
557         0x160/4, 0x168/4, 0x170/4, 0x178/4,
558         0x200/4, 0x208/4, 0x210/4, 0x218/4,
559 };
560 static  int     pcfg[] = {
561         0x1c0/4, 0x1c8/4, 0x1d0/4, 0x1d8/4,
562         0x230/4, 0x238/4, 0x240/4, 0x248/4,
563 };
564 static  int     psc[] = {
565         0x180/4, 0x184/4, 0x188/4, 0x18c/4,
566         0x220/4, 0x224/4, 0x228/4, 0x22c/4,
567 };
568 static  int     vscfg[] = {
569         0x1e0/4, 0x1e8/4, 0x1f0/4, 0x1f8/4,
570         0x250/4, 0x258/4, 0x260/4, 0x268/4,
571 };
572 #define sstatus(d)      (d)->ctlr->reg[psc[(d)->driveno]]
573
574 static char*
575 dstate(uint s)
576 {
577         int i;
578
579         for(i = 0; s; i++)
580                 s >>= 1;
581         return diskstates[i];
582 }
583
584 static char*
585 dnam(Drive *d)
586 {
587         if(d->unit)
588                 return d->unit->name;
589         return d->name;
590 }
591
592 static uvlong border = 0x0001020304050607ull;
593 static uvlong lorder = 0x0706050403020100ull;
594
595 static uvlong
596 getle(uchar *t, int w)
597 {
598         uint i;
599         uvlong r;
600
601         r = 0;
602         for(i = w; i != 0; )
603                 r = r<<8 | t[--i];
604         return r;
605 }
606
607 static void
608 putle(uchar *t, uvlong r, int w)
609 {
610         uchar *o, *f;
611         uint i;
612
613         f = (uchar*)&r;
614         o = (uchar*)&lorder;
615         for(i = 0; i < w; i++)
616                 t[o[i]] = f[i];
617 }
618
619 static uvlong
620 getbe(uchar *t, int w)
621 {
622         uint i;
623         uvlong r;
624
625         r = 0;
626         for(i = 0; i < w; i++)
627                 r = r<<8 | t[i];
628         return r;
629 }
630
631 static void
632 putbe(uchar *t, uvlong r, int w)
633 {
634         uchar *o, *f;
635         uint i;
636
637         f = (uchar*)&r;
638         o = (uchar*)&border + (sizeof border-w);
639         for(i = 0; i < w; i++)
640                 t[i] = f[o[i]];
641 }
642
643 static int phyrtab[] = {Phy0, Phy1};
644 static void
645 phyenable(Ctlr *c, Drive *d)
646 {
647         uint i, u, reg, m;
648
649         i = d->driveno;
650         reg = phyrtab[i > 3];
651         i &= 3;
652         i = 1<<i;
653         u = pcicfgr32(c->pci, reg);
654         m = i*(Phypdwn | Phydisable | Phyen);
655         if((u & m) == Phyen)
656                 return;
657         m = i*(Phypdwn | Phydisable);
658         u &= ~m;
659         u |= i*Phyen;
660         pcicfgw32(c->pci, reg, u);
661 }
662
663 static void
664 regtxreset(Drive *d)
665 {
666         uint i, u, m;
667         Ctlr *c = d->ctlr;
668
669         i = d->driveno;
670         u = c->reg[Portcfg1];
671         m = (Regen|Xmten)<<i;
672         u &= ~m;
673         c->reg[Portcfg1] = u;
674         delay(1);
675         c->reg[Portcfg1] = u | m;
676 }
677
678 /* aka comreset? */
679 static void
680 phyreset(Drive *d)
681 {
682         uint i, u, reg;
683         Ctlr *c;
684
685         c = d->ctlr;
686         phyenable(c, d);
687
688         i = d->driveno;
689         reg = phyrtab[i > 3];
690         i &= 3;
691         i = 1<<i;
692         u = pcicfgr32(c->pci, reg);
693         pcicfgw32(c->pci, reg, u | i*Phyrst);
694         delay(5);
695         pcicfgw32(c->pci, reg, u);
696
697         sstatus(d) |= Shreset;
698         while(sstatus(d) & Shreset);
699                 ;
700 }
701
702 static void
703 reset(Drive *d)
704 {
705         regtxreset(d);
706         phyreset(d);
707 }
708
709 /*
710  * sata/sas register reads through wormhole
711  */
712 static uint
713 ssread(Ctlr *c, int port, uint r)
714 {
715         c->reg[Cmda] = r + 4*port;
716         return c->reg[Cmdd];
717 }
718
719 static void
720 sswrite(Ctlr *c, int port, int r, uint u)
721 {
722         c->reg[Cmda] = r + 4*port;
723         c->reg[Cmdd] = u;
724 }
725
726 /*
727  * port configuration r/w through wormhole
728  */
729 static uint
730 pcread(Ctlr *c, uint port, uint r)
731 {
732         c->reg[pcfg[port]] = r;
733         return c->reg[pcfg[port] + 1];
734 }
735
736 static void
737 pcwrite(Ctlr *c, uint port, uint r, uint u)
738 {
739         c->reg[pcfg[port] + 0] = r;
740         c->reg[pcfg[port] + 1] = u;
741 }
742
743 /*
744  * vendor specific r/w through wormhole
745  */
746 static uint
747 vsread(Ctlr *c, uint port, uint r)
748 {
749         c->reg[vscfg[port]] = r;
750         return c->reg[vscfg[port] + 1];
751 }
752
753 static void
754 vswrite(Ctlr *c, uint port, uint r, uint u)
755 {
756         c->reg[vscfg[port] + 0] = r;
757         c->reg[vscfg[port] + 1] = u;
758 }
759
760 /*
761  * gpio wormhole
762  */
763 static uint
764 gpread(Ctlr *c, uint r)
765 {
766         c->reg[Gpioa] = r;
767         return c->reg[Gpiod];
768 }
769
770 static void
771 gpwrite(Ctlr *c, uint r, uint u)
772 {
773         c->reg[Gpioa] = r;
774         c->reg[Gpiod] = u;
775 }
776
777 static uint*
778 getsigfis(Drive *d, uint *fis)
779 {
780         uint i;
781
782         for(i = 0; i < 4; i++)
783                 fis[i] = pcread(d->ctlr, d->driveno, Psig + 4*i);
784         return fis;
785 }
786
787 static uint
788 getsig(Drive *d)
789 {
790         uint fis[4];
791
792         return fistosig((uchar*)getsigfis(d, fis));
793 }
794
795 static uint
796 ci(Drive *d)
797 {
798         return ssread(d->ctlr, d->driveno, Ci);
799 }
800
801 static void
802 unsetci(Drive *d)
803 {
804         uint i;
805
806         i = 1<<d->driveno;
807         sswrite(d->ctlr, d->driveno, Ci, i);
808         while(ci(d) & i)
809                 microdelay(1);
810 }
811
812 static uint
813 gettask(Drive *d)
814 {
815         return ssread(d->ctlr, d->driveno, Task);
816 }
817
818 static void
819 tprint(Drive *d, uint t)
820 {
821         uint s;
822
823         s = sstatus(d);
824         dprint("%s: err task %ux sstat %ux\n", dnam(d), t, s);
825 }
826
827 static int
828 cmdactive(void *v)
829 {
830         Cmd *x;
831
832         x = v;
833         return (x->cflag & Done) != 0;
834 }
835
836 static int
837 mswait(Cmd *x, int ms)
838 {
839         uint u, tk0;
840
841         if(up){
842                 tk0 = Ticks;
843                 while(waserror())
844                         ;
845                 tsleep(x, cmdactive, x, ms);
846                 poperror();
847                 ms -= TK2MS(Ticks - tk0);
848         }else
849                 while(ms-- && cmdactive(x))
850                         delay(1);
851 //      ilock(cmd->d);
852         u = x->cflag;
853         x->cflag = 0;
854 //      iunlock(cmd->d)
855
856         if(u == (Done | Active))
857                 return 0;
858         if((u & Done) == 0){
859                 u |= Noverdict | Creset | Timeout;
860                 print("cmd timeout ms:%d %ux\n", ms, u);
861         }
862         return u;
863 }
864
865 static void
866 setstate(Drive *d, int state)
867 {
868         ilock(d);
869         d->state = state;
870         iunlock(d);
871 }
872
873 static void
874 esleep(int ms)
875 {
876         if(waserror())
877                 return;
878         tsleep(&up->sleep, return0, 0, ms);
879         poperror();
880 }
881
882 static int
883 waitready(Drive *d)
884 {
885         ulong s, i, δ;
886
887         for(i = 0; i < 15000; i += 250){
888                 if(d->state & (Dreset | Dportreset | Dnew))
889                         return 1;
890                 δ = Ticks - d->lastseen;
891                 if(d->state == Dnull || δ > 10*1000)
892                         return -1;
893                 ilock(d);
894                 s = sstatus(d);
895                 iunlock(d);
896                 if((s & Sphyrdy) == 0 && δ > 1500)
897                         return -1;
898                 if(d->state == Dready && (s & Sphyrdy))
899                         return 0;
900                 esleep(250);
901         }
902         print("%s: not responding; offline: %.8ux\n", dnam(d), sstatus(d));
903         setstate(d, Doffline);
904         return -1;
905 }
906
907 static int
908 lockready(Drive *d)
909 {
910         int i, r;
911
912         for(i = 0; ; i++){
913                 qlock(d);
914                 if((r = waitready(d)) != 1)
915                         return r;
916                 qunlock(d);
917                 if(i == Nms*10)
918                         break;
919                 esleep(1);
920         }
921         return -1;
922 }
923
924 static int
925 command(Drive *d, uint cmd, int ms)
926 {
927         uint s, n, m, i;
928         Ctlr *c;
929
930         c = d->ctlr;
931         i = d->driveno;
932         m = 1<<i;
933         n = cmd | Ditor | i*Dsatareg | m*Dphyno | i*Dcslot;
934 //      print("cqwp\t%.8ux : n %ux : d%d; \n", c->cq[0], n, i);
935         d->cmd->cflag = Active;
936         ilock(c);
937         s = c->dqwp++;
938         c->dq[s&Qmask] = n;
939         c->reg[Dqwp] = s&Qmask;
940         iunlock(c);
941 //      print(" dq slot %d\n", s);
942         d->intick = Ticks;              /* move to mswait? */
943         return mswait(d->cmd, ms);
944 }
945
946 static int
947 buildfis(Drive *d, SDreq *r, void *data, int n)
948 {
949         Aprdt *p;
950         Cmd *x;
951         Cmdh *h;
952
953         x = d->cmd;
954         memmove(x->cfis, r->cmd, r->clen);
955
956         h = x->cmdh;
957         memset(h, 0, 16);
958         h->fislen[0] = 5;
959         h->len[0] = 0;
960
961         if(data != nil){
962                 h->len[0] = 1;
963                 p = x;
964                 p->dba = PCIWADDR(data);
965                 p->dbahi = Pciwaddrh(data);
966                 p->count = n;
967         }
968         return command(d, Dsata, 10*1000);
969 }
970
971 static int
972 build(Drive *d, int rw, void *data, int n, vlong lba)
973 {
974         Aprdt *p;
975         Cmd *x;
976         Cmdh *h;
977
978         x = d->cmd;
979         rwfis(d, x->cfis, rw, n, lba);
980
981         h = x->cmdh;
982         memset(h, 0, 16);
983         h->fislen[0] = 5;
984         h->len[0] = 1;                  /* one prdt entry */
985
986         p = x;
987         p->dba = PCIWADDR(data);
988         p->dbahi = Pciwaddrh(data);
989         p->count = d->secsize*n;
990
991         return command(d, Dsata, 10*1000);
992 }
993
994 enum{
995         Rnone   = 1,
996         Rdma    = 0x00,         /* dma setup; length 0x1b */
997         Rpio    = 0x20,         /* pio setup; length 0x13 */
998         Rd2h    = 0x40,         /* d2h register;length 0x13 */
999         Rsdb    = 0x58,         /* set device bits; length 0x08 */
1000 };
1001
1002 static uint fisotab[8] = {
1003 [0]     Rnone,
1004 [1]     Rd2h,
1005 [2]     Rpio,
1006 [3]     Rnone,
1007 [4]     Rsdb,
1008 [5]     Rnone,
1009 [6]     Rnone,
1010 [7]     Rnone,
1011 };
1012
1013 static uint
1014 fisoffset(Drive *d, int mustbe)
1015 {
1016         uint t, r;
1017
1018         t = gettask(d) & 0x70000;
1019         r = fisotab[t >> 16];
1020         if(r == Rnone || (mustbe != 0 && r != mustbe))
1021                 return 0;
1022         return 0x800 + 0x100*d->driveno + r;
1023 }
1024
1025 /* need to find a non-atapi-specific way of doing this */
1026 static uint
1027 atapixfer(Drive *d, uint n)
1028 {
1029         uchar *u;
1030         uint i, x;
1031
1032         if((i = fisoffset(d, Rd2h)) == 0)
1033                 return 0;
1034         u = d->ctlr->fis + i;
1035         x = u[Flba16]<<8 | u[Flba8];
1036         if(x > n){
1037                 x = n;
1038                 print("%s: atapixfer %ux %ux\n", dnam(d), x, n);
1039         }
1040         return x;
1041 }
1042
1043 static int
1044 buildpkt(Drive *d, SDreq *r, void *data, int n)
1045 {
1046         int rv;
1047         Aprdt *p;
1048         Cmd *x;
1049         Cmdh *h;
1050
1051         x = d->cmd;
1052         atapirwfis(d, x->cfis, r->cmd, r->clen, n);
1053
1054         h = x->cmdh;
1055         memset(h, 0, 16);
1056         h->satactl = Latapi;
1057         h->fislen[0] = 5;
1058         h->len[0] = 1;          /* one prdt entry */
1059
1060         if(data != nil){
1061                 p = x;
1062                 p->dba = PCIWADDR(data);
1063                 p->dbahi = Pciwaddrh(data);
1064                 p->count = n;
1065         }
1066         rv = command(d, Dsata, 10*1000);
1067         if(rv == 0)
1068                 r->rlen = atapixfer(d, n);
1069         return rv;
1070 }
1071
1072 /*
1073  * ata 7, required for sata, requires that all devices "support"
1074  * udma mode 5,   however sata:pata bridges allow older devices
1075  * which may not.  the innodisk satadom, for example allows
1076  * only udma mode 2.  on the assumption that actual udma is
1077  * taking place on these bridges, we set the highest udma mode
1078  * available, or pio if there is no udma mode available.
1079  */
1080 static int
1081 settxmode(Drive *d, uchar f)
1082 {
1083         Cmd *x;
1084         Cmdh *h;
1085
1086         x = d->cmd;
1087         if(txmodefis(d, x->cfis, f) == -1)
1088                 return 0;
1089
1090         h = x->cmdh;
1091         memset(h, 0, 16);
1092         h->fislen[0] = 5;
1093
1094         return command(d, Dsata, 3*1000);
1095 }
1096
1097 static int
1098 setfeatures(Drive *d, uchar f, uint w)
1099 {
1100         Cmd *x;
1101         Cmdh *h;
1102
1103         x = d->cmd;
1104         featfis(d, x->cfis, f);
1105
1106         h = x->cmdh;
1107         memset(h, 0, 16);
1108         h->fislen[0] = 5;
1109
1110         return command(d, Dsata, w);
1111 }
1112
1113 static int
1114 mvflushcache(Drive *d)
1115 {
1116         Cmd *x;
1117         Cmdh *h;
1118
1119         x = d->cmd;
1120         flushcachefis(d, x->cfis);
1121
1122         h = x->cmdh;
1123         memset(h, 0, 16);
1124         h->fislen[0] = 5;
1125
1126         return command(d, Dsata, 60*1000);
1127 }
1128
1129 static int
1130 identify0(Drive *d, void *id)
1131 {
1132         Aprdt *p;
1133         Cmd *x;
1134         Cmdh *h;
1135
1136         x = d->cmd;
1137         identifyfis(d, x->cfis);
1138
1139         h = x->cmdh;
1140         memset(h, 0, 16);
1141         h->fislen[0] = 5;
1142         h->len[0] = 1;          /* one prdt entry */
1143
1144         memset(id, 0, 0x200);
1145         p = x;
1146         p->dba = PCIWADDR(id);
1147         p->dbahi = Pciwaddrh(id);
1148         p->count = 0x200;
1149
1150         return command(d, Dsata, 3*1000);
1151 }
1152
1153 static int
1154 identify(Drive *d)
1155 {
1156         int i, n;
1157         vlong osectors, s;
1158         uchar oserial[21];
1159         ushort *id;
1160         SDunit *u;
1161
1162         id = d->info;
1163         for(i = 0;; i++){
1164                 if(i > 5 || identify0(d, id) != 0)
1165                         return -1;
1166                 n = idpuis(id);
1167                 if(n & Pspinup && setfeatures(d, 7, 20*1000) == -1)
1168                         dprint("%s: puis spinup fail\n", dnam(d));
1169                 if(n & Pidready)
1170                         break;
1171         }
1172
1173         s = idfeat(d, id);
1174         if(s == -1)
1175                 return -1;
1176         if((d->feat&Dlba) == 0){
1177                 dprint("%s: no lba support\n", dnam(d));
1178                 return -1;
1179         }
1180         osectors = d->sectors;
1181         memmove(oserial, d->serial, sizeof d->serial);
1182
1183         d->sectors = s;
1184         d->secsize = idss(d, id);
1185
1186         idmove(d->serial, id+10, 20);
1187         idmove(d->firmware, id+23, 8);
1188         idmove(d->model, id+27, 40);
1189         d->wwn = idwwn(d, id);
1190
1191         u = d->unit;
1192         memset(u->inquiry, 0, sizeof u->inquiry);
1193         u->inquiry[2] = 2;
1194         u->inquiry[3] = 2;
1195         u->inquiry[4] = sizeof u->inquiry - 4;
1196         memmove(u->inquiry+8, d->model, 40);
1197
1198         if(osectors != s || memcmp(oserial, d->serial, sizeof oserial)){
1199                 d->drivechange = 1;
1200                 u->sectors = 0;
1201         }
1202         return 0;
1203 }
1204
1205 /* open address fises */
1206 enum{
1207         Initiator               = 0x80,
1208         Openaddr        = 1,
1209         Awms            = 0x8000,
1210         Smp             = 0,
1211         Ssp             = 1,
1212         Stp             = 2,
1213         Spd15           = 8,
1214         Spd30           = 9,
1215 };
1216
1217 static void
1218 oafis(Cfis *f, uchar *c, int type)
1219 {
1220         c[0] = Initiator | type<<4 | Openaddr;
1221         c[1] = Spd30;                           /* botch; just try 3gbps */
1222         if(type == Smp)
1223                 memset(c + 2, 0xff, 2);
1224         else
1225                 memmove(c + 2, f->ict, 2);
1226         memmove(c + 4, f->tsasaddr, 8);         /* dest "port identifier" §4.2.6 */
1227         memmove(c + 12, f->ssasaddr, 8);
1228 }
1229
1230 /* sas fises */
1231 static int
1232 sasfis(Cfis*, uchar *c, SDreq *r)
1233 {
1234         memmove(c, r->cmd, r->clen);
1235         if(r->clen < 16)
1236                 memset(c + r->clen, 0, 16 - r->clen);
1237         return 0;
1238 }
1239
1240 /* sam3 §4.9.4 single-level lun structure */
1241 static void
1242 scsilun8(uchar *c, int l)
1243 {
1244         memset(c, 0, 8);
1245         if(l < 255)
1246                 c[1] = l;
1247         else if(l < 16384){
1248                 c[0] = 1<<6 | l>>8;
1249                 c[1] = l;
1250         }else
1251                 print("bad lun %d\n", l);
1252 }
1253
1254 static void
1255 iuhdr(SDreq *r, uchar *c, int fburst)
1256 {
1257         scsilun8(c, r->lun);
1258         c[8] = 0;
1259         c[9] = 0;
1260         if(fburst)
1261                 c[9] = 0x80;
1262 }
1263
1264 static void
1265 ssphdr(Cfis *x, uchar *c, int ftype)
1266 {
1267         memset(c, 0, 0x18);
1268         c[0] = ftype;
1269         sasbhash(c + 1, x->tsasaddr);
1270         sasbhash(c + 5, x->ssasaddr);
1271 }
1272
1273 /* debugging */
1274 static void
1275 dump(uchar *u, uint n)
1276 {
1277         uint i;
1278
1279         if(n > 100)
1280                 n = 100;
1281         for(i = 0; i < n; i += 4){
1282                 print("%.2d  %.2ux%.2ux%.2ux%.2ux", i, u[i], u[i + 1], u[i + 2], u[i + 3]);
1283                 print("\n");
1284         }
1285 }
1286
1287 static void
1288 prsense(uchar *u, uint n)
1289 {
1290         print("sense data %d: \n", n);
1291         dump(u, n);
1292 }
1293
1294 static void
1295 priu(uchar *u, uint n)
1296 {
1297         print("iu %d: \n", n);
1298         dump(u, n);
1299 }
1300
1301 /*
1302  * other suspects:
1303  * key  asc/q
1304  * 02   0401    becoming ready
1305  *      040b    target port in standby state
1306  *      0b01    overtemp
1307  *      0b0[345]        background *
1308  *      0c01    write error - recovered with auto reallocation
1309  *      0c02    write error - auto reallocation failed
1310  *      0c03    write error - recommend reassignment
1311  *      17*     recovered data
1312  *      18*     recovered data
1313  *      5d*     smart-style reporting (disk/smart handles)
1314  *      5e*     power state change
1315  */
1316
1317 static int
1318 classifykey(int asckey)
1319 {
1320         if(asckey == 0x062901 || asckey == 0x062900){
1321                 /* power on */
1322                 dprint("power on sense\n");
1323                 return SDretry;
1324         }
1325         return SDcheck;
1326 }
1327
1328 /* spc3 §4.5 */
1329 static int
1330 sasrspck(Drive *d, SDreq *r, int min)
1331 {
1332         char *p;
1333         int rv;
1334         uchar *u, *s;
1335         uint l, fmt, n, keyasc;
1336
1337         u = d->cmd->rsp;
1338         s = u + 24;
1339         dprint("status %d datapres %d\n", u[11], u[10]);
1340         switch(u[10]){
1341         case 1:
1342                 l = getbe(u + 20, 4);
1343                 /*
1344                  * this is always a bug because we don't do
1345                  * task mgmt
1346                  */
1347                 print("%s: bug: task data %d min %d\n", dnam(d), l, min);
1348                 return SDcheck;
1349         case 2:
1350                 l = getbe(u + 16, 4);
1351                 n = sizeof r->sense;
1352                 if(l < n)
1353                         n = l;
1354                 memmove(r->sense, s, n);
1355                 fmt = s[0] & 0x7f;
1356                 keyasc = (s[2] & 0xf)<<16 | s[12]<<8 | s[13];
1357                 rv = SDcheck;
1358                 /* spc3 §4.5.3; 0x71 is deferred. */
1359                 if(n >= 18 && (fmt == 0x70 || fmt == 0x71)){
1360                         rv = classifykey(keyasc);
1361                         p = "";
1362                         if(rv == SDcheck){
1363                                 r->flags |= SDvalidsense;
1364                                 p = "valid";
1365                         }
1366                         dprint("sense %.6ux %s\n", keyasc, p);
1367                 }else
1368                         prsense(s, l);
1369                 return rv;
1370         default:
1371                 print("%s: sasrspck: spurious\n", dnam(d));
1372                 priu(u, 24);
1373                 prsense(s, 0x30);
1374                 return SDcheck;
1375         }
1376 }
1377
1378 static int
1379 buildsas(Drive *d, SDreq *r, uchar *data, int n)
1380 {
1381         int w, try, fburst;
1382         Aprdt *p;
1383         Cmd *x;
1384         Cmdh *h;
1385
1386         try = 0;
1387 top:
1388         fburst = 0;             /* Firstburst? */
1389         x = d->cmd;
1390         /* ssphdr(d, x->sspfh, 6); */
1391         iuhdr(r, x->sasiu, fburst);
1392         w = 0;
1393         if(r->clen > 16)
1394                 w = r->clen - 16 + 3>> 2;
1395         x->sasiu[11] = w;
1396         sasfis(d, x->sasiu + 12, r);
1397
1398         h = x->cmdh;
1399         memset(h, 0, 16);
1400         h->sasctl = Tlretry | /*Vrfylen |*/ Sspcmd | fburst;
1401         h->fislen[0] = sizeof x->sspfh + 12 + 16 + 4*w >> 2;
1402         h->maxrsp = 0xff;
1403         if(n)
1404                 h->len[0] = 1;
1405         h->ttag[0] = 1;
1406         *(uint*)h->dlen = n;
1407
1408         if(n){
1409                 p = x;
1410                 p->dba = PCIWADDR(data);
1411                 p->dbahi = Pciwaddrh(data);
1412                 p->count = n;
1413         }
1414         switch(w = command(d, Dssp, 10*1000)){
1415         case 0:
1416                 r->status = sdsetsense(r, SDok, 0, 0, 0);
1417                 return 0;
1418         case Response | Done | Active:
1419                 r->status = sasrspck(d, r, 0);
1420                 if(r->status == SDok)
1421                         return 0;
1422                 if(r->status == SDretry){
1423                         if(try++ < 2)
1424                                 goto top;
1425                         r->status |= SDvalidsense;
1426                 }
1427                 return w | Sense;
1428         default:
1429                 r->status = sdsetsense(r, SDcheck, 4, 24, 0);
1430                 return w;
1431         }
1432 }
1433
1434 static uint
1435 analyze(Drive *d, Statb *b)
1436 {
1437         uint u, r, t;
1438
1439         r = 0;
1440         u = *(uint*)b->error;
1441         if(u & Eissuestp){
1442                 r |= Error;
1443                 unsetci(d);
1444         }
1445         if(u & Etask && (d->feat & Datapi) == 0){
1446                 t = gettask(d);
1447                 if(t & 1)
1448                         tprint(d, t);
1449                 if(t & Efatal<<8 || t & (ASbsy|ASdrq))
1450                         r |= Noverdict|Atareset;
1451                 if(t&Adhrs && t&33)
1452                         r |= Noverdict|Atareset;
1453                 else
1454                         r |= Error;
1455         }
1456         if(u & (Ererr | Ebadprot)){
1457                 /* sas thing */
1458                 print("%s: sas error %.8ux\n", dnam(d), u);
1459                 r |= Error;
1460         }
1461         if(u & ~(Ebadprot | Ererr | Etask | Eissuestp))
1462                 print("%s: analyze %.8ux\n", dnam(d), u);
1463
1464         return r;
1465 }
1466
1467 static void
1468 updatedone(Ctlr *c)
1469 {
1470         uint a, e, i, u, slot;
1471         Cmd *x;
1472         Drive *d;
1473
1474         e = c->cq[0];
1475         if(e == 0xfff)
1476                 return;
1477         if(e > Qmask)
1478                 print("sdodin: bug: bad cqrp %ux\n", e);
1479         e = e+1 & Qmask;
1480         for(i = c->cqrp; i != e; i = i+1 & Qmask){
1481                 u = c->cq[1 + i];
1482                 c->cq[1 + i] = 0;
1483                 slot = u & 0xfff;
1484                 u &= ~slot;
1485                 d = c->drive + slot;
1486                 x = d->cmd;
1487                 if(u & Cqdone){
1488                         x->cflag |= Done;
1489                         u &= ~Cqdone;
1490                 }
1491                 if(u & (Crxfr | Cgood)){
1492                         if((u & Cgood) == 0)
1493                                 x->cflag |= Response;
1494                         u &= ~(Crxfr | Cgood);
1495                 }
1496                 if(u & Cerr){
1497                         dprint("%s: Cerr ..\n", dnam(d));
1498                         a = analyze(d, x);
1499                         x->cflag |= Done | a;
1500                         u &= ~Cerr;
1501                 }
1502                 if(x->cflag & Done)
1503                         wakeup(x);
1504                 if(u)
1505                         print("%s: odd bits %.8ux\n", dnam(d), u);
1506         }
1507 if(i == c->cqrp)print("odin: spur done\n");
1508         c->cqrp = i;
1509 }
1510
1511 static void
1512 updatedrive(Drive *d)
1513 {
1514         uint cause, s0, ewake;
1515         char *name;
1516         Cmd *x;
1517         static uint last, tk;
1518
1519         ewake = 0;
1520         cause = d->ctlr->reg[pis[d->driveno]];
1521         d->ctlr->reg[pis[d->driveno]] = cause;
1522         x = d->cmd;
1523         name = dnam(d);
1524
1525         if(last != cause || Ticks - tk > 5*1000){
1526                 dprint("%s: ca %ux ta %ux\n", name, cause, gettask(d));
1527                 tk = Ticks;
1528         }
1529         if(cause & (Phyunrdy | Phyidto | Pisataup | Pisasup)){
1530                 s0 = d->state;
1531                 if(cause == (Phyrdy | Comw)){
1532                         d->type = 0;
1533                         d->state = Dnopower;
1534                 }
1535                 switch(cause & (Phyunrdy | Phyidto | Phyidok | Sigrx)){
1536                 case Phyunrdy:
1537                         d->state = Dmissing;
1538                         if(sstatus(d) & Sphyrdy){
1539                                 if(d->type != 0)
1540                                         d->state = Dnew;
1541                                 else
1542                                         d->state = Dreset;
1543                         }
1544                         break;
1545                 case Phyidto:
1546                         d->type = 0;
1547                         d->state = Dmissing;
1548                         break;
1549                 case Phyidok:
1550                         d->type = Sas;
1551                         d->state = Dnew;
1552                         break;
1553                 case Sigrx:
1554                         d->type = Sata;
1555                         d->state = Dnew;
1556                         break;
1557                 }
1558                 dprint("%s: %s → %s [Apcrs] %s %ux\n", name, dstate(s0),
1559                         dstate(d->state), type[d->type], sstatus(d));
1560                 if(s0 == Dready && d->state != Dready)
1561                         idprint("%s: pulled\n", name);
1562                 if(d->state != Dready || ci(d))
1563                         ewake |= Done | Noverdict;
1564         }else if(cause & Piburp)
1565                 ewake |= Done | Noverdict;
1566         else if(cause & Pireset)
1567                 ewake |= Done | Noverdict | Creset;
1568         else if(cause & Piunsupp){
1569                 print("%s: unsupported h/w: %.8ux\n", name, cause);
1570                 ewake |= Done | Error;
1571                 d->type = 0;
1572                 d->state = Doffline;
1573         }
1574         if(ewake){
1575                 dprint("%s: ewake %.8ux\n", name, ewake);
1576                 unsetci(d);
1577                 x->cflag |= ewake;
1578                 wakeup(x);
1579         }
1580         last = cause;
1581 }
1582
1583 static int
1584 satareset(Drive *d)
1585 {
1586         ilock(d->ctlr);
1587         unsetci(d);
1588         iunlock(d->ctlr);
1589         if(gettask(d) & (ASdrq|ASbsy))
1590                 return -1;
1591         if(settxmode(d, d->udma) != 0)
1592                 return -1;
1593         return 0;
1594 }
1595
1596 static int
1597 msriopkt(SDreq *r, Drive *d)
1598 {
1599         int n, count, try, max, flag, task;
1600         uchar *cmd;
1601
1602         cmd = r->cmd;
1603         aprint("%02ux %02ux %c %d %p\n", cmd[0], cmd[2], "rw"[r->write],
1604                 r->dlen, r->data);
1605         r->rlen = 0;
1606         count = r->dlen;
1607         max = 65536;
1608
1609         for(try = 0; try < 10; try++){
1610                 n = count;
1611                 if(n > max)
1612                         n = max;
1613                 if(lockready(d) == -1)
1614                         return SDeio;
1615                 flag = buildpkt(d, r, r->data, n);
1616                 task = gettask(d);
1617                 if(flag & Atareset && satareset(d) == -1)
1618                         setstate(d, Dreset);
1619                 qunlock(d);
1620                 if(flag & Noverdict){
1621                         if(flag & Creset)
1622                                 setstate(d, Dreset);
1623                         print("%s: retry\n", dnam(d));
1624                         continue;
1625                 }
1626                 if(flag & Error){
1627                         if((task & Eidnf) == 0)
1628                                 print("%s: i/o error %ux\n", dnam(d), task);
1629                         return r->status = SDcheck;
1630                 }
1631                 return r->status = SDok;
1632         }
1633         print("%s: bad disk\n", dnam(d));
1634         return r->status = SDcheck;
1635 }
1636
1637 static int
1638 msriosas(SDreq *r, Drive *d)
1639 {
1640         int try, flag;
1641
1642         for(try = 0; try < 10; try++){
1643                 if(lockready(d) == -1)
1644                         return SDeio;
1645                 flag = buildsas(d, r, r->data, r->dlen);
1646                 qunlock(d);
1647                 if(flag & Noverdict){
1648                         if(flag & Creset)
1649                                 setstate(d, Dreset);
1650                         print("%s: retry\n", dnam(d));
1651                         continue;
1652                 }
1653                 if(flag & Error){
1654                         print("%s: i/o error\n", dnam(d));
1655                         return r->status = SDcheck;
1656                 }
1657                 r->rlen = r->dlen;      /* fishy */
1658                 return r->status;               /* set in sasrspck */
1659
1660         }
1661         print("%s: bad disk\n", dnam(d));
1662         sdsetsense(r, SDcheck, 3, r->write? 0xc00: 0x11, 0);
1663         return r->status = SDcheck;
1664 }
1665
1666 static int
1667 flushcache(Drive *d)
1668 {
1669         int i;
1670
1671         i = -1;
1672         if(lockready(d) == 0)
1673                 i = mvflushcache(d);
1674         qunlock(d);
1675         return i;
1676 }
1677
1678 static int
1679 msriosata(SDreq *r, Drive *d)
1680 {
1681         char *name;
1682         int i, n, count, try, max, flag, task;
1683         uvlong lba;
1684         uchar *cmd, *data;
1685         SDunit *unit;
1686
1687         unit = r->unit;
1688         cmd = r->cmd;
1689         name = dnam(d);
1690
1691         if(cmd[0] == 0x35 || cmd[0] == 0x91){
1692                 if(flushcache(d) == 0)
1693                         return sdsetsense(r, SDok, 0, 0, 0);
1694                 return sdsetsense(r, SDcheck, 3, 0xc, 2);
1695         }
1696         if((i = sdfakescsi(r)) != SDnostatus){
1697                 r->status = i;
1698                 return i;
1699         }
1700         if((i = sdfakescsirw(r, &lba, &count, nil)) != SDnostatus)
1701                 return i;
1702         max = 128;
1703         if(d->feat & Dllba)
1704                 max = 65536;
1705         try = 0;
1706         data = r->data;
1707         while(count > 0){
1708                 n = count;
1709                 if(n > max)
1710                         n = max;
1711                 if(lockready(d) == -1)
1712                         return SDeio;
1713                 flag = build(d, r->write, data, n, lba);
1714                 task = gettask(d);
1715                 if(flag & Atareset && satareset(d) == -1)
1716                         setstate(d, Dreset);
1717                 qunlock(d);
1718                 if(flag & Noverdict){
1719                         if(flag & Creset)
1720                                 setstate(d, Dreset);
1721                         if(++try == 2){
1722                                 print("%s: bad disk\n", name);
1723                                 return r->status = SDeio;
1724                         }
1725                         iprint("%s: retry %lld [%.8ux]\n", name, lba, task);
1726                         continue;
1727                 }
1728                 if(flag & Error){
1729                         iprint("%s: i/o error %ux @%,lld\n", name, task, lba);
1730                         return r->status = SDeio;
1731                 }
1732                 count -= n;
1733                 lba   += n;
1734                 data += n*unit->secsize;
1735         }
1736         r->rlen = data - (uchar*)r->data;
1737         r->status = SDok;
1738         return SDok;
1739 }
1740
1741 static int
1742 msrio(SDreq *r)
1743 {
1744         Ctlr *c;
1745         Drive *d;
1746         SDunit *u;
1747
1748         u = r->unit;
1749         c = u->dev->ctlr;
1750         d = c->drive + u->subno;
1751         if(d->feat & Datapi)
1752                 return msriopkt(r, d);
1753         if(d->type == Sas)
1754                 return msriosas(r, d);
1755         if(d->type == Sata)
1756                 return msriosata(r, d);
1757         return sdsetsense(r, SDcheck, 3, 0x04, 0x24);
1758 }
1759
1760 /*
1761  * §6.1.9.5
1762  * not clear that this is necessary
1763  * we should know that it's a d2h from the status.
1764  * pio returns pio setup fises.  hw bug?
1765  */
1766 static int
1767 sdr(SDreq *r, Drive *d, int st)
1768 {
1769         uint i;
1770
1771         if(i = fisoffset(d, 0/*Rd2h*/))
1772                 memmove(r->cmd, d->ctlr->fis + i, 16);
1773         else
1774                 memset(r->cmd, 0xff, 16);
1775         r->status = st;
1776         return st;
1777 }
1778
1779 /*
1780  * handle oob requests;
1781  *    restrict & sanitize commands
1782  */
1783 static int
1784 fisreqchk(Sfis *f, SDreq *r)
1785 {
1786         uchar *c;
1787
1788         if((r->ataproto & Pprotom) == Ppkt)
1789                 return SDnostatus;
1790         if(r->clen != 16)
1791                 error("bad command length"); //error(Eio);
1792         c = r->cmd;
1793         if(c[0] == 0xf0){
1794                 sigtofis(f, r->cmd);
1795                 return r->status = SDok;
1796         }
1797         c[0] = H2dev;
1798         c[1] = Fiscmd;
1799         c[7] |= Ataobs;
1800         return SDnostatus;
1801 }
1802
1803 static int
1804 msataio(SDreq *r)
1805 {
1806         char *name;
1807         int try, flag, task;
1808         Ctlr *c;
1809         Drive *d;
1810         SDunit *u;
1811         int (*build)(Drive*, SDreq*, void*, int);
1812
1813         u = r->unit;
1814         c = u->dev->ctlr;
1815         d = c->drive + u->subno;
1816         name = dnam(d);
1817
1818         if(d->type != Sata)
1819                 error("not sata");
1820         if(r->cmd[0] == 0xf1){
1821                 d->state = Dreset;
1822                 return r->status = SDok;
1823         }
1824         if((r->status = fisreqchk(d, r)) != SDnostatus)
1825                 return r->status;
1826         build = buildfis;
1827         if((r->ataproto & Pprotom) == Ppkt)
1828                 build = buildpkt;
1829
1830         for(try = 0; try < 10; try++){
1831                 if(lockready(d) == -1)
1832                         return SDeio;
1833                 flag = build(d, r, r->data, r->dlen);
1834                 task = gettask(d);
1835                 if(flag & Atareset && satareset(d) == -1)
1836                         setstate(d, Dreset);
1837                 qunlock(d);
1838                 if(flag & Noverdict){
1839                         if(flag & (Timeout | Creset))
1840                                 setstate(d, Dreset);
1841                         else if(task & Eabrt<<8){
1842                                 /* assume bad cmd */
1843                                 r->status = SDeio;
1844                                 return SDeio;
1845                         }
1846                         print("%s: retry\n", name);
1847                         continue;
1848                 }
1849                 if(flag & Error){
1850                         print("%s: i/o error %.8ux\n", name, task);
1851                         r->status = SDeio;
1852                         return SDeio;
1853                 }
1854                 if(build != buildpkt)
1855                         r->rlen = r->dlen;
1856                 return sdr(r, d, SDok);
1857         }
1858         print("%s: bad disk\n", name);
1859         return sdr(r, d, SDeio);
1860 }
1861
1862 static void
1863 msinterrupt(Ureg *, void *a)
1864 {
1865         Ctlr *c;
1866         uint u, i;
1867         static uint cnt;
1868
1869         c = a;
1870         ilock(c);
1871         u = c->reg[Cis];
1872         if(u == 0){
1873                 iunlock(c);
1874                 return;
1875         }
1876         c->reg[Cis] = u & ~Iclr;
1877         if(u != Cdone && cnt++ < 15)
1878                 print("sdodin: irq %s %.8ux\n", c->sdev->ifc->name, u);
1879         for(i = 0; i < 8; i++)
1880                 if(u & (1<<i)*(Portirq|Portstop))
1881                         updatedrive(c->drive + i);
1882         if(u & Srsirq){
1883                 u = c->reg[Csis];
1884                 c->reg[Csis] = u;
1885                 for(i = 0; i < 8; i++)
1886                         if(u & 1<<i)
1887                                 updatedrive(c->drive + i);
1888         }
1889         if(u & Cdone){
1890                 updatedone(c);
1891                 c->reg[Cis] = Cdone;
1892         }
1893         iunlock(c);
1894 }
1895
1896 static char*
1897 mc(Drive *d)
1898 {
1899         char *s;
1900
1901         s = "";
1902         if(d->drivechange)
1903                 s = "[newdrive]";
1904         return s;
1905 }
1906
1907 static int
1908 newsatadrive(Drive *d)
1909 {
1910         uint task;
1911
1912         task = gettask(d);
1913         if((task & 0xffff) == 0x80)
1914                 return SDretry;
1915         setfissig(d, getsig(d));
1916         if(identify(d) != 0){
1917                 dprint("%s: identify failure\n", dnam(d));
1918                 return SDeio;
1919         }
1920         if(d->feat & Dpower && setfeatures(d, 0x85, 3*1000)  != 0){
1921                 d->feat &= ~Dpower;
1922                 if(satareset(d) == -1)
1923                         return SDeio;
1924         }
1925         if(settxmode(d, d->udma)  != 0){
1926                 dprint("%s: can't set tx mode\n", dnam(d));
1927                 return SDeio;
1928         }
1929         return SDok;
1930 }
1931
1932 static void
1933 newoaf(Drive *d, int type)
1934 {
1935         uint ict, i;
1936         uvlong sa;
1937         Ctlr *c;
1938
1939         i = d->driveno;
1940         c = d->ctlr;
1941
1942         sa = pcread(c, i, Pawwn + 0);
1943         sa |= (uvlong)pcread(c, i, Pawwn + 4)<<32;
1944         putbe(d->tsasaddr, sa, 8);
1945         memmove(d->ssasaddr, d->ssasaddr, 8);
1946         ict = pcread(c, i, Pwwn + 8);
1947         putbe(d->ict, ict, 2);
1948         oafis(d, d->cmd->oaf, type);
1949 }
1950
1951 static int
1952 sasinquiry(Drive *d)
1953 {
1954         SDreq r;
1955         SDunit *u;
1956
1957         u = d->unit;
1958         memset(&r, 0, sizeof r);
1959         r.cmd[0] = 0x12;
1960         r.cmd[4] = 0xff;
1961         r.clen = 6;
1962         r.unit = u;
1963
1964         return buildsas(d, &r, u->inquiry, sizeof u->inquiry);
1965 }
1966
1967 static int
1968 sastur(Drive *d)
1969 {
1970         SDreq r;
1971         SDunit *u;
1972
1973         u = d->unit;
1974         memset(&r, 0, sizeof r);
1975         r.clen = 6;
1976         r.unit = u;
1977         return buildsas(d, &r, 0, 0);
1978 }
1979
1980 static int
1981 sasvpd(Drive *d, uchar *buf, int l)
1982 {
1983         SDreq r;
1984         SDunit *u;
1985
1986         u = d->unit;
1987         memset(&r, 0, sizeof r);
1988         r.cmd[0] = 0x12;
1989         r.cmd[1] = 1;
1990         r.cmd[2] = 0x80;
1991         r.cmd[4] = l;
1992         r.clen = 6;
1993         r.unit = u;
1994         return buildsas(d, &r, buf, l);
1995 }
1996
1997 static int
1998 sascapacity10(Drive *d, uchar *buf, int l)
1999 {
2000         SDreq r;
2001         SDunit *u;
2002
2003         u = d->unit;
2004         memset(&r, 0, sizeof r);
2005         r.cmd[0] = 0x25;
2006         r.clen = 10;
2007         r.unit = u;
2008         return buildsas(d, &r, buf, l);
2009 }
2010
2011 static int
2012 sascapacity16(Drive *d, uchar *buf, int l)
2013 {
2014         SDreq r;
2015         SDunit *u;
2016
2017         u = d->unit;
2018         memset(&r, 0, sizeof r);
2019         r.cmd[0] = 0x9e;
2020         r.cmd[1] = 0x10;
2021         r.cmd[13] = l;
2022         r.clen = 16;
2023         r.unit = u;
2024         return buildsas(d, &r, buf, l);
2025 }
2026
2027 static void
2028 frmove(char *p, uchar *c, int n)
2029 {
2030         char *op, *e;
2031
2032         memmove(p, c, n);
2033         op = p;
2034         p[n] = 0;
2035         for(p = p + n - 1; p > op && *p == ' '; p--)
2036                 *p = 0;
2037         e = p;
2038         p = op;
2039         while(*p == ' ')
2040                 p++;
2041         memmove(op, p, n - (e - p));
2042 }
2043
2044 static void
2045 chkinquiry(Drive *d, uchar *c)
2046 {
2047         char buf[32], buf2[32], omod[sizeof d->model];
2048
2049         memmove(omod, d->model, sizeof d->model);
2050         frmove(buf, c + 8, 8);
2051         frmove(buf2, c + 16, 16);
2052         snprint(d->model, sizeof d->model, "%s %s", buf, buf2);
2053         frmove(d->firmware, c + 23, 4);
2054         if(memcmp(omod, d->model, sizeof omod) != 0)
2055                 d->drivechange = 1;
2056 }
2057
2058 static void
2059 chkvpd(Drive *d, uchar *c, int n)
2060 {
2061         char buf[sizeof d->serial];
2062         int l;
2063
2064         l = c[3];
2065         if(l > n)
2066                 l = n;
2067         frmove(buf, c + 4, l);
2068         if(strcmp(buf, d->serial) != 0)
2069                 d->drivechange = 1;
2070         memmove(d->serial, buf, sizeof buf);
2071 }
2072
2073 static int
2074 adjcapacity(Drive *d, uvlong ns, uint nss)
2075 {
2076         if(ns != 0)
2077                 ns++;
2078         if(nss == 2352)
2079                 nss = 2048;
2080         if(d->sectors != ns || d->secsize != nss){
2081                 d->drivechange = 1;
2082                 d->sectors = ns;
2083                 d->secsize = nss;
2084         }
2085         return 0;
2086 }
2087
2088 static int
2089 chkcapacity10(uchar *p, uvlong *ns, uint *nss)
2090 {
2091         *ns = getbe(p, 4);
2092         *nss = getbe(p + 4, 4);
2093         return 0;
2094 }
2095
2096 static int
2097 chkcapacity16(uchar *p, uvlong *ns, uint *nss)
2098 {
2099         *ns = getbe(p, 8);
2100         *nss = getbe(p + 8, 4);
2101         return 0;
2102 }
2103
2104 static int
2105 sasprobe(Drive *d)
2106 {
2107         uchar buf[0x40];
2108         int r;
2109         uint nss;
2110         uvlong ns;
2111
2112         if((r = sastur(d)) != 0)
2113                 return r;
2114         if((r = sasinquiry(d)) != 0)
2115                 return r;
2116         chkinquiry(d, d->unit->inquiry);
2117         /* vpd 0x80 (unit serial) is not mandatory */
2118         if((r = sasvpd(d, buf, sizeof buf)) == 0)
2119                 chkvpd(d, buf, sizeof buf);
2120         else if(r & (Error | Timeout))
2121                 return r;
2122         else{
2123                 if(d->serial[0])
2124                         d->drivechange = 1;
2125                 d->serial[0] = 0;
2126         }
2127         if((r = sascapacity10(d, buf, sizeof buf)) != 0)
2128                 return r;
2129         chkcapacity10(buf, &ns, &nss);
2130         if(ns == 0xffffffff){
2131                 if((r = sascapacity16(d, buf, sizeof buf)) != 0)
2132                         return r;
2133                 chkcapacity16(buf, &ns, &nss);
2134         }
2135         adjcapacity(d, ns, nss);
2136
2137         return 0;
2138 }
2139
2140 static int
2141 newsasdrive(Drive *d)
2142 {
2143         memset(d->cmd->rsp, 0, sizeof d->cmd->rsp);
2144         newoaf(d, Ssp);
2145         switch(sasprobe(d) & (Error | Noverdict | Timeout | Sense)){
2146         case Error:
2147         case Timeout:
2148                 return SDeio;
2149         case Sense:
2150         case Noverdict:
2151                 return SDretry;
2152         }
2153         return SDok;
2154 }
2155
2156 static int
2157 newdrive(Drive *d)
2158 {
2159         char *t;
2160         int r;
2161
2162         memset(&d->Sfis, 0, sizeof d->Sfis);
2163         memset(&d->Cfis, 0, sizeof d->Cfis);
2164         qlock(d);
2165         switch(d->type){
2166         case Sata:
2167                 r = newsatadrive(d);
2168                 break;
2169         case Sas:
2170                 r = newsasdrive(d);
2171                 break;
2172         default:
2173                 print("%s: bug: martian drive %d\n", dnam(d), d->type);
2174                 qunlock(d);
2175                 return -1;
2176         }
2177         t = type[d->type];
2178         switch(r){
2179         case SDok:
2180                 idprint("%s: %s %,lld sectors\n", dnam(d), t, d->sectors);
2181                 idprint("  %s %s %s %s\n", d->model, d->firmware, d->serial, mc(d));
2182                 setstate(d, Dready);
2183                 break;
2184         case SDeio:
2185                 idprint("%s: %s can't be initialized\n", dnam(d), t);
2186                 setstate(d, Derror);
2187         case SDretry:
2188                 break;
2189         }
2190         qunlock(d);
2191         return r;
2192 }
2193
2194 static void
2195 statechange(Drive *d)
2196 {
2197         switch(d->state){
2198         case Dmissing:
2199         case Dnull:
2200         case Doffline:
2201                 d->drivechange = 1;
2202                 d->unit->sectors = 0;
2203                 break;
2204         case Dready:
2205                 d->wait = 0;
2206                 break;
2207         }
2208 }
2209
2210 /*
2211  * we don't respect running commands.  botch?
2212  */
2213 static void
2214 checkdrive(Drive *d, int i)
2215 {
2216         uint s;
2217
2218         if(d->unit == nil)
2219                 return;
2220         ilock(d);
2221         s = sstatus(d);
2222         d->wait++;
2223         if(s & Sphyrdy)
2224                 d->lastseen = Ticks;
2225         if(s != olds[i]){
2226                 dprint("%s: status: %.6ux -> %.6ux: %s\n",
2227                         dnam(d), olds[i], s, dstate(d->state));
2228                 olds[i] = s;
2229                 statechange(d);
2230         }
2231         switch(d->state){
2232         case Dnull:
2233         case Dmissing:
2234                 if(d->type != 0 && s & Sphyrdy)
2235                         d->state = Dnew;
2236                 break;
2237         case Dnopower:
2238                 phyreset(d);    /* spinup */
2239                 break;
2240         case Dnew:
2241                 if(d->wait % 6 != 0)
2242                         break;
2243                 iunlock(d);
2244                 newdrive(d);
2245                 ilock(d);
2246                 break;
2247         case Dready:
2248                 d->wait = 0;
2249                 break;
2250         case Derror:
2251                 d->wait = 0;
2252                 d->state = Dreset;
2253         case Dreset:
2254                 if(d->wait % 40 != 0)
2255                         break;
2256                 reset(d);
2257                 break;
2258         case Doffline:
2259         case Dportreset:
2260                 break;
2261         }
2262         iunlock(d);
2263 }
2264
2265 static void
2266 mskproc(void*)
2267 {
2268         int i;
2269
2270         while(waserror())
2271                 ;
2272         for(;;){
2273                 tsleep(&up->sleep, return0, 0, Nms);
2274                 for(i = 0; i < nmsdrive; i++)
2275                         checkdrive(msdrive[i], i);
2276         }
2277 }
2278
2279 static void
2280 ledcfg(Ctlr *c, int port, uint cfg)
2281 {
2282         uint u, r, s;
2283
2284         r = Drivectl + (port>>2)*Gpiooff;
2285         s = 15 - port & 3;
2286         s *= 8;
2287         u = gpread(c, r);
2288         u &= ~(0xff << s);
2289         u |= cfg<<s;
2290         gpwrite(c, r, u);
2291 }
2292
2293 static uchar ses2ledstd[Ibpilast] = {
2294 [Ibpinone]      Lhigh*Aled,
2295 [Ibpinormal]    Lsof*Aled | Llow*Locled | Llow*Errled,
2296 [Ibpirebuild]   Lsof*Aled | Llow*Locled | Llow*Errled,
2297 [Ibpilocate]    Lsof*Aled | Lblinka*Locled | Llow*Errled,
2298 [Ibpispare]     Lsof*Aled | Llow*Locled| Lblinka*Errled,
2299 [Ibpipfa]               Lsof*Aled | Lblinkb*Locled | Llow*Errled,
2300 [Ibpifail]              Lsof*Aled | Llow*Locled | Lhigh*Errled,
2301 [Ibpicritarray] Lsof*Aled,
2302 [Ibpifailarray] Lsof*Aled,
2303 };
2304
2305 static uchar ses2led[Ibpilast] = {
2306 [Ibpinone]      Lhigh*Aled,
2307 [Ibpinormal]    Lsof*Aled | Llow*Locled | Llow*Errled,
2308 [Ibpirebuild]   Lsof*Aled | Lblinkaneg*Locled | Llow*Errled,
2309 [Ibpilocate]    Lsof*Aled | Lhigh*Locled | Llow*Errled,
2310 [Ibpispare]     Lsof*Aled | Lblinka*Locled| Llow*Errled,
2311 [Ibpipfa]               Lsof*Aled | Lblinkb*Locled | Llow*Errled,
2312 [Ibpifail]              Lsof*Aled | Llow*Locled | Lhigh*Errled,
2313 [Ibpicritarray] Lsof*Aled,
2314 [Ibpifailarray] Lsof*Aled,
2315 };
2316
2317 static void
2318 setupled(Ctlr *c)
2319 {
2320         int i, l, blen;
2321         pcicfgw32(c->pci, Gpio, pcicfgr32(c->pci, Gpio) | 1<<7);
2322
2323         /*
2324          * configure a for 4hz (1/8s on and 1/8s off)
2325          * configure b for 1hz (2/8s on and 6/8s off)
2326          */
2327         l = 3 + c->ndrive >> 2;
2328         blen = 3*24 - 1;
2329         for(i = 0; i < l*Gpiooff; i += Gpiooff){
2330                 gpwrite(c, Sgconf0 + i, blen*Autolen | Blinkben | Blinkaen | Sgpioen);
2331                 gpwrite(c, Sgconf1 + i, 1*Bhi | 1*Blo | 1*Ahi | 7*Alo);
2332                 gpwrite(c, Sgconf3 + i, 7<<20 | Sdoutauto);
2333         }
2334 }
2335
2336 static void
2337 trebuild(Ctlr *c, Drive *d, int dno, uint i)
2338 {
2339         uchar bits;
2340
2341         if(0 && d->led == Ibpirebuild){
2342                 switch(i%19){
2343                 case 0:
2344                         bits = 0;
2345                         break;
2346                 case 1:
2347                         bits = ses2led[Ibpirebuild] | Lblinka*Locled;
2348                         break;
2349                 case 3:
2350                         bits = ses2led[Ibpirebuild] | Lblinkb*Locled;
2351                         break;
2352                 }
2353         }else
2354                 bits =  ses2led[d->led];
2355         if(d->ledbits != bits)
2356                 ledcfg(c, dno, bits);
2357 }
2358
2359 static long
2360 odinledr(SDunit *u, Chan *ch, void *a, long n, vlong off)
2361 {
2362         Ctlr *c;
2363         Drive *d;
2364
2365         c = u->dev->ctlr;
2366         d = c->drive + u->subno;
2367         return ledr(d, ch, a, n, off);
2368 }
2369
2370 static long
2371 odinledw(SDunit *u, Chan *ch, void *a, long n, vlong off)
2372 {
2373         Ctlr *c;
2374         Drive *d;
2375
2376         c = u->dev->ctlr;
2377         d = c->drive + u->subno;
2378         return ledw(d, ch, a, n, off);
2379 }
2380
2381 /*
2382  * this kproc can probablly go when i figure out
2383  * how to program the manual blinker
2384  */
2385 static void
2386 ledkproc(void*)
2387 {
2388         uint i, j;
2389         Drive *d;
2390
2391         for(i = 0; i < nmsdrive; i++){
2392                 d = msdrive[i];
2393                 d->nled = 2;            /* how to know? */
2394         }
2395         for(i = 0; i < nmsctlr; i++)
2396                 pcicfgw32(msctlr[i].pci, Gpio, pcicfgr32(msctlr[i].pci, Gpio) | 1<<7);
2397         for(i = 0; i < nmsctlr; i++)
2398                 setupled(msctlr + i);
2399         for(i = 0; ; i++){
2400                 esleep(Nms);
2401                 for(j = 0; j < nmsdrive; j++){
2402                         d = msdrive[j];
2403                         trebuild(d->ctlr, d, j, i);
2404                 }
2405         }
2406 }
2407
2408 static int
2409 msenable(SDev *s)
2410 {
2411         char buf[32];
2412         Ctlr *c;
2413         static int once;
2414
2415         c = s->ctlr;
2416         ilock(c);
2417         if(!c->enabled){
2418                 if(once++ == 0)
2419                         kproc("odin", mskproc, 0);
2420                 pcisetbme(c->pci);
2421                 snprint(buf, sizeof buf, "%s (%s)", s->name, s->ifc->name);
2422                 intrenable(c->pci->intl, msinterrupt, c, c->pci->tbdf, buf);
2423 //              c->reg[Cis] |= Swirq1;          /* force initial interrupt. */
2424                 c->enabled = 1;
2425         }
2426         iunlock(c);
2427         return 1;
2428 }
2429
2430 static int
2431 msdisable(SDev *s)
2432 {
2433         char buf[32];
2434         Ctlr *c;
2435
2436         c = s->ctlr;
2437         ilock(c);
2438 //      disable(c->hba);
2439         snprint(buf, sizeof buf, "%s (%s)", s->name, s->ifc->name);
2440         intrdisable(c->pci->intl, msinterrupt, c, c->pci->tbdf, buf);
2441         pciclrbme(c->pci);
2442         c->enabled = 0;
2443         iunlock(c);
2444         return 1;
2445 }
2446
2447 static int
2448 scsiish(Drive *d)
2449 {
2450         return d->type == Sas || d->feat & Datapi;
2451 }
2452
2453 static int
2454 msonline(SDunit *u)
2455 {
2456         int r;
2457         Ctlr *c;
2458         Drive *d;
2459
2460         c = u->dev->ctlr;
2461         d = c->drive + u->subno;
2462         r = 0;
2463
2464         if(scsiish(d)){
2465                 if(!d->drivechange)
2466                         return r;
2467                 r = scsionline(u);
2468                 if(r > 0)
2469                         d->drivechange = 0;
2470                 return r;
2471         }
2472         ilock(d);
2473         if(d->drivechange){
2474                 r = 2;
2475                 d->drivechange = 0;
2476                 u->sectors = d->sectors;
2477                 u->secsize = d->secsize;
2478         } else if(d->state == Dready)
2479                 r = 1;
2480         iunlock(d);
2481         return r;
2482 }
2483
2484 static void
2485 verifychk(Drive *d)
2486 {
2487         int w;
2488
2489         if(!up)
2490                 checkdrive(d, d->driveno);
2491         for(w = 0; w < 12000; w += 210){
2492                 if(d->state == Dready)
2493                         break;
2494                 if(w > 2000 && d->state != Dnew)
2495                         break;
2496                 if((sstatus(d) & Sphyrdy) == 0)
2497                         break;
2498                 if(!up)
2499                         checkdrive(d, d->driveno);
2500                 esleep(210);
2501         }
2502 }
2503
2504 static int
2505 msverify(SDunit *u)
2506 {
2507         int chk;
2508         Ctlr *c;
2509         Drive *d;
2510         static int once;
2511
2512         c = u->dev->ctlr;
2513         d = c->drive + u->subno;
2514         ilock(c);
2515         ilock(d);
2516         chk = 0;
2517         if(d->unit == nil){
2518                 d->unit = u;
2519                 sdaddfile(u, "led", 0644, eve, odinledr, odinledw);
2520                 once++;
2521                 if(once == nmsctlr)
2522                         kproc("mvled", ledkproc, 0);
2523                 chk = 1;
2524         }
2525         iunlock(d);
2526         iunlock(c);
2527
2528         /*
2529          * since devsd doesn't know much about hot-plug drives,
2530          * we need to give detected drives a chance.
2531          */
2532         if(chk){
2533                 reset(d);
2534                 verifychk(d);
2535         }
2536         return 1;
2537 }
2538
2539 static uint*
2540 map(Pcidev *p, int bar)
2541 {
2542         uintptr io;
2543
2544         io = p->mem[bar].bar & ~0xf;
2545         return (uint*)vmap(io, p->mem[bar].size);
2546 }
2547
2548 /* §5.1.3 */
2549 static void
2550 initmem(Ctlr *c)
2551 {
2552         c->fis = malloc(0x800 + 0x100*16);      /* §6.1.9.3 */
2553         c->cl = malloc(nelem(c->cq)*sizeof *c->cl);
2554         c->cmdtab = malloc(Nctlrdrv*sizeof *c->cmdtab);
2555         if(c->fis == nil || c->cl == nil || c->cmdtab == nil)
2556                 panic("sdodin: no memory");
2557         c->reg[Fisbase + 0] = PCIWADDR(c->fis);
2558         c->reg[Fisbase + 1] = Pciwaddrh(c->fis);
2559         c->reg[Cqbase + 0] = PCIWADDR(c->cq);
2560         c->reg[Cqbase + 1] = Pciwaddrh(c->cq);
2561         c->reg[Cqcfg] = Cqen | Noattn | nelem(c->cq) - 1;
2562         c->reg[Dqbase + 0] = PCIWADDR(c->dq);
2563         c->reg[Dqbase + 1] = Pciwaddrh(c->dq);
2564         c->reg[Dqcfg] = Dqen | nelem(c->dq);
2565         c->reg[Clbase + 0] = PCIWADDR(c->cl);
2566         c->reg[Clbase + 1] = Pciwaddrh(c->cl);
2567 }
2568
2569 /* §5.1.2 */
2570 static void
2571 startup(Ctlr *c)
2572 {
2573         c->reg[Gctl] |= Reset;
2574         while(c->reg[Gctl] & Reset)
2575                 ;
2576         initmem(c);
2577         c->reg[Cie] = Swirq1 | 0xff*Portstop | 0xff*Portirq | Srsirq | Issstop | Cdone;
2578         c->reg[Gctl] |= Intenable;
2579         c->reg[Portcfg0] = Rmask*Regen | Dataunke | Rsple | Framele;
2580         c->reg[Portcfg1] = Rmask*Regen | 0xff*Xmten | /*Cmdirq |*/ Fisen | Resetiss | Issueen;
2581         c->reg[Csie] = ~0;
2582         sswrite(c, 0, Pwdtimer, 0x7fffff);
2583 }
2584
2585 static void
2586 forcetype(Ctlr*)
2587 {
2588         /*
2589          * if we want to force sas/sata, here's where to do it.
2590          */
2591 }
2592
2593 static void
2594 setupcmd(Drive *d)
2595 {
2596         int i;
2597         Ctlr *c;
2598         Cmd *cmd;
2599         Cmdh *h;
2600
2601         i = d->driveno;
2602         c = d->ctlr;
2603         d->cmd = c->cmdtab + i;
2604         d->cmd->cmdh = c->cl + i;
2605         cmd = d->cmd;
2606         h = cmd->cmdh;
2607
2608         /* prep the precomputable bits in the cmd hdr §6.1.4 */
2609         putle(h->ctab, Pciw64(&cmd->Ctab), sizeof h->ctab);
2610         putle(h->oaf, Pciw64(&cmd->Oaf), sizeof h->oaf);
2611         putle(h->statb, Pciw64(&cmd->Statb), sizeof h->statb);
2612         putle(h->prd, Pciw64(&cmd->Aprdt), sizeof h->prd);
2613
2614         /* finally, set up the wide-port participating bit */
2615         pcwrite(c, i, Pwidecfg, 1<<i);
2616 }
2617
2618 static void
2619 phychk(Ctlr *c, Drive *d)
2620 {
2621         int i;
2622         uvlong u;
2623         static uchar src[8] = {0x50, 0x03, 0x04, 0x80};
2624
2625         i = d->driveno;
2626         memmove(d->ssasaddr, src, 8);
2627         u = getbe(d->ssasaddr, 8);
2628         pcwrite(c, i, Paddr + 0, u);
2629         pcwrite(c, i, Paddr + 4, u>>32);
2630 }
2631
2632 static SDev*
2633 mspnp(void)
2634 {
2635         int i, nunit;
2636         Ctlr *c;
2637         Drive *d;
2638         Pcidev *p;
2639         SDev **ll, *s, *s0;
2640         static int done;
2641
2642         if(done++)
2643                 return nil;
2644         s0 = nil;
2645         ll = &s0;
2646         for(p = nil; (p = pcimatch(p, 0x11ab, 0x6485)) != nil; ){
2647                 if(nmsctlr == Nctlr){
2648                         print("sdodin: too many controllers\n");
2649                         break;
2650                 }
2651                 c = msctlr + nmsctlr;
2652                 s = sdevs + nmsctlr;
2653                 memset(c, 0, sizeof *c);
2654                 memset(s, 0, sizeof *s);
2655                 if((c->reg = map(p, Mebar)) == 0){
2656                         print("sdodin: bar %#p in use\n", c->reg);
2657                         continue;
2658                 }
2659                 pcienable(p);
2660                 nunit = p->did>>4 & 0xf;
2661                 s->ifc = &sdodinifc;
2662                 s->idno = 'a' + nmsctlr;
2663                 s->ctlr = c;
2664                 c->sdev = s;
2665                 c->pci = p;
2666                 c->ndrive = s->nunit = nunit;
2667                 i = pcicfgr32(p, Dctl) & ~(7<<12);
2668                 pcicfgw32(p, Dctl, i | 4<<12);
2669
2670                 print("#S/sd%c: odin ii sata/sas with %d ports\n", s->idno, nunit);
2671                 startup(c);
2672                 forcetype(c);
2673                 for(i = 0; i < nunit; i++){
2674                         d = c->drive + i;
2675                         d->driveno = i;
2676                         d->sectors = 0;
2677                         d->ctlr = c;
2678                         setupcmd(d);
2679                         snprint(d->name, sizeof d->name, "odin%d.%d", nmsctlr, i);
2680                         msdrive[nmsdrive + i] = d;
2681 //                      phychk(c, d);
2682                         c->reg[pis[i] + 1] =
2683                                 Sync | Phyerr | Stperr | Crcerr |
2684                                 Linkrx | Martianfis | Anot | Bist | Sigrx |
2685                                 Phyunrdy | Martiantag | Bnot | Comw |
2686                                 Portsel | Hreset | Phyidto | Phyidok |
2687                                 Hresetok | Phyrdy;
2688                 }
2689                 nmsdrive += nunit;
2690                 nmsctlr++;
2691                 *ll = s;
2692                 ll = &s->next;
2693         }
2694         return s0;
2695 }
2696
2697 static char*
2698 msrctlsata(Drive *d, char *p, char *e)
2699 {
2700         p = seprint(p, e, "flag\t");
2701         p = pflag(p, e, d);
2702         p = seprint(p, e, "udma\t%d\n", d->udma);
2703         return p;
2704 }
2705
2706 static char*
2707 rctldebug(char *p, char *e, Ctlr *c, Drive *d)
2708 {
2709         int i;
2710         uvlong sasid;
2711
2712         i = d->driveno;
2713         p = seprint(p, e, "sstatus\t%.8ux\n", sstatus(d));
2714 //      p = seprint(p, e, "cis\t%.8ux %.8ux\n", c->reg[Cis], c->reg[Cie]);
2715 //      p = seprint(p, e, "gis\t%.8ux\n", c->reg[Gis]);
2716         p = seprint(p, e, "pis\t%.8ux %.8ux\n", c->reg[pis[i]], c->reg[pis[i] + 1]);
2717         p = seprint(p, e, "sis\t%.8ux\n", c->reg[Csis]);
2718         p = seprint(p, e, "cqwp\t%.8ux\n", c->cq[0]);
2719         p = seprint(p, e, "cerror\t%.8ux %.8ux\n", *(uint*)d->cmd->error, *(uint*)(d->cmd->error+4));
2720         p = seprint(p, e, "task\t%.8ux\n", gettask(d));
2721         p = seprint(p, e, "ptype\t%.8ux\n", c->reg[Ptype]);
2722         p = seprint(p, e, "satactl\t%.8ux\n", pcread(c, i, Psatactl));  /* appears worthless */
2723         p = seprint(p, e, "info %.8ux %.8ux\n", pcread(c, i, Pinfo), pcread(c, i, Painfo));
2724         p = seprint(p, e, "physts       %.8ux\n", pcread(c, i, Pphysts));
2725         p = seprint(p, e, "widecfg      %.8ux\n", pcread(c, i, Pwidecfg));
2726         sasid = pcread(c, i, Pwwn + 0);
2727         sasid |= (uvlong)pcread(c, i, Pwwn + 4)<<32;
2728         p = seprint(p, e, "wwn  %.16llux %.8ux\n", sasid, pcread(c, i, Pwwn + 8));
2729         sasid = pcread(c, i, Pawwn + 0);
2730         sasid |= (uvlong)pcread(c, i, Pawwn + 4)<<32;
2731         p = seprint(p, e, "awwn %.16llux\n", sasid);
2732         sasid = pcread(c, i, Paddr + 0);
2733         sasid |= (uvlong)pcread(c, i, Paddr + 4)<<32;
2734         p = seprint(p, e, "sasid        %.16llux\n", sasid);
2735         return p;
2736 }
2737
2738 static int
2739 msrctl(SDunit *u, char *p, int l)
2740 {
2741         char *e, *op;
2742         Ctlr *c;
2743         Drive *d;
2744
2745         if((c = u->dev->ctlr) == nil)
2746                 return 0;
2747         d = c->drive + u->subno;
2748         e = p + l;
2749         op = p;
2750         p = seprint(p, e, "state\t%s\n", dstate(d->state));
2751         p = seprint(p, e, "type\t%s", type[d->type]);
2752         if(d->type == Sata)
2753                 p = seprint(p, e, " sig %.8ux", getsig(d));
2754         p = seprint(p, e, "\n");
2755         if(d->state == Dready){
2756                 p = seprint(p, e, "model\t%s\n", d->model);
2757                 p = seprint(p, e, "serial\t%s\n", d->serial);
2758                 p = seprint(p, e, "firm\t%s\n", d->firmware);
2759                 p = seprint(p, e, "wwn\t%llux\n", d->wwn);
2760                 p = msrctlsata(d, p, e);
2761         }
2762         p = rctldebug(p, e, c, d);
2763         p = seprint(p, e, "geometry %llud %lud\n", d->sectors, u->secsize);
2764         return p - op;
2765 }
2766
2767 static void
2768 forcestate(Drive *d, char *state)
2769 {
2770         int i;
2771
2772         for(i = 1; i < nelem(diskstates); i++)
2773                 if(strcmp(state, diskstates[i]) == 0)
2774                         break;
2775         if(i == nelem(diskstates))
2776                 error(Ebadctl);
2777         ilock(d);
2778         d->state = 1 << i - 1;
2779         statechange(d);
2780         iunlock(d);
2781 }
2782
2783 static int
2784 mswctl(SDunit *u, Cmdbuf *cmd)
2785 {
2786         char **f;
2787         Ctlr *c;
2788         Drive *d;
2789
2790         c = u->dev->ctlr;
2791         d = c->drive + u->subno;
2792         f = cmd->f;
2793         if(strcmp(f[0], "state") == 0)
2794                 forcestate(d, f[1]? f[1]: "null");
2795         else
2796                 cmderror(cmd, Ebadctl);
2797         return 0;
2798 }
2799
2800 static int
2801 mswtopctl(SDev*, Cmdbuf *cmd)
2802 {
2803         char **f;
2804         int *v;
2805
2806         f = cmd->f;
2807         v = 0;
2808         if(strcmp(f[0], "debug") == 0)
2809                 v = &debug;
2810         else if(strcmp(f[0], "idprint") == 0)
2811                 v = &idebug;
2812         else if(strcmp(f[0], "aprint") == 0)
2813                 v = &adebug;
2814         else
2815                 cmderror(cmd, Ebadctl);
2816         if(cmd->nf == 1)
2817                 *v ^= 1;
2818         else if(cmd->nf == 2)
2819                 *v = strcmp(f[1], "on") == 0;
2820         else
2821                 cmderror(cmd, Ebadarg);
2822         return 0;
2823 }
2824
2825 SDifc sdodinifc = {
2826         "odin",
2827         mspnp,
2828         nil,
2829         msenable,
2830         msdisable,
2831         msverify,
2832         msonline,
2833         msrio,
2834         msrctl,
2835         mswctl,
2836         scsibio,
2837         nil,            /* probe */
2838         nil,            /* clear */
2839         nil,
2840         mswtopctl,
2841         msataio,
2842 };