]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/sdodin.c
merge
[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         /*
936          * xinc doesn't return the previous value and i can't
937          * figure out how to do this without a lock
938          *      s = _xinc(&c->dqwp);
939          */
940         d->cmd->cflag = Active;
941         ilock(c);
942         s = c->dqwp++;
943         c->dq[s&Qmask] = n;
944         c->reg[Dqwp] = s&Qmask;
945         iunlock(c);
946 //      print(" dq slot %d\n", s);
947         d->intick = Ticks;              /* move to mswait? */
948         return mswait(d->cmd, ms);
949 }
950
951 static int
952 buildfis(Drive *d, SDreq *r, void *data, int n)
953 {
954         Aprdt *p;
955         Cmd *x;
956         Cmdh *h;
957
958         x = d->cmd;
959         memmove(x->cfis, r->cmd, r->clen);
960
961         h = x->cmdh;
962         memset(h, 0, 16);
963         h->fislen[0] = 5;
964         h->len[0] = 0;
965
966         if(data != nil){
967                 h->len[0] = 1;
968                 p = x;
969                 p->dba = PCIWADDR(data);
970                 p->dbahi = Pciwaddrh(data);
971                 p->count = n;
972         }
973         return command(d, Dsata, 10*1000);
974 }
975
976 static int
977 build(Drive *d, int rw, void *data, int n, vlong lba)
978 {
979         Aprdt *p;
980         Cmd *x;
981         Cmdh *h;
982
983         x = d->cmd;
984         rwfis(d, x->cfis, rw, n, lba);
985
986         h = x->cmdh;
987         memset(h, 0, 16);
988         h->fislen[0] = 5;
989         h->len[0] = 1;                  /* one prdt entry */
990
991         p = x;
992         p->dba = PCIWADDR(data);
993         p->dbahi = Pciwaddrh(data);
994         p->count = d->secsize*n;
995
996         return command(d, Dsata, 10*1000);
997 }
998
999 enum{
1000         Rnone   = 1,
1001         Rdma    = 0x00,         /* dma setup; length 0x1b */
1002         Rpio    = 0x20,         /* pio setup; length 0x13 */
1003         Rd2h    = 0x40,         /* d2h register;length 0x13 */
1004         Rsdb    = 0x58,         /* set device bits; length 0x08 */
1005 };
1006
1007 static uint fisotab[8] = {
1008 [0]     Rnone,
1009 [1]     Rd2h,
1010 [2]     Rpio,
1011 [3]     Rnone,
1012 [4]     Rsdb,
1013 [5]     Rnone,
1014 [6]     Rnone,
1015 [7]     Rnone,
1016 };
1017
1018 static uint
1019 fisoffset(Drive *d, int mustbe)
1020 {
1021         uint t, r;
1022
1023         t = gettask(d) & 0x70000;
1024         r = fisotab[t >> 16];
1025         if(r == Rnone || (mustbe != 0 && r != mustbe))
1026                 return 0;
1027         return 0x800 + 0x100*d->driveno + r;
1028 }
1029
1030 /* need to find a non-atapi-specific way of doing this */
1031 static uint
1032 atapixfer(Drive *d, uint n)
1033 {
1034         uchar *u;
1035         uint i, x;
1036
1037         if((i = fisoffset(d, Rd2h)) == 0)
1038                 return 0;
1039         u = d->ctlr->fis + i;
1040         x = u[Flba16]<<8 | u[Flba8];
1041         if(x > n){
1042                 x = n;
1043                 print("%s: atapixfer %ux %ux\n", dnam(d), x, n);
1044         }
1045         return x;
1046 }
1047
1048 static int
1049 buildpkt(Drive *d, SDreq *r, void *data, int n)
1050 {
1051         int rv;
1052         Aprdt *p;
1053         Cmd *x;
1054         Cmdh *h;
1055
1056         x = d->cmd;
1057         atapirwfis(d, x->cfis, r->cmd, r->clen, n);
1058
1059         h = x->cmdh;
1060         memset(h, 0, 16);
1061         h->satactl = Latapi;
1062         h->fislen[0] = 5;
1063         h->len[0] = 1;          /* one prdt entry */
1064
1065         if(data != nil){
1066                 p = x;
1067                 p->dba = PCIWADDR(data);
1068                 p->dbahi = Pciwaddrh(data);
1069                 p->count = n;
1070         }
1071         rv = command(d, Dsata, 10*1000);
1072         if(rv == 0)
1073                 r->rlen = atapixfer(d, n);
1074         return rv;
1075 }
1076
1077 /*
1078  * ata 7, required for sata, requires that all devices "support"
1079  * udma mode 5,   however sata:pata bridges allow older devices
1080  * which may not.  the innodisk satadom, for example allows
1081  * only udma mode 2.  on the assumption that actual udma is
1082  * taking place on these bridges, we set the highest udma mode
1083  * available, or pio if there is no udma mode available.
1084  */
1085 static int
1086 settxmode(Drive *d, uchar f)
1087 {
1088         Cmd *x;
1089         Cmdh *h;
1090
1091         x = d->cmd;
1092         if(txmodefis(d, x->cfis, f) == -1)
1093                 return 0;
1094
1095         h = x->cmdh;
1096         memset(h, 0, 16);
1097         h->fislen[0] = 5;
1098
1099         return command(d, Dsata, 3*1000);
1100 }
1101
1102 static int
1103 setfeatures(Drive *d, uchar f, uint w)
1104 {
1105         Cmd *x;
1106         Cmdh *h;
1107
1108         x = d->cmd;
1109         featfis(d, x->cfis, f);
1110
1111         h = x->cmdh;
1112         memset(h, 0, 16);
1113         h->fislen[0] = 5;
1114
1115         return command(d, Dsata, w);
1116 }
1117
1118 static int
1119 mvflushcache(Drive *d)
1120 {
1121         Cmd *x;
1122         Cmdh *h;
1123
1124         x = d->cmd;
1125         flushcachefis(d, x->cfis);
1126
1127         h = x->cmdh;
1128         memset(h, 0, 16);
1129         h->fislen[0] = 5;
1130
1131         return command(d, Dsata, 60*1000);
1132 }
1133
1134 static int
1135 identify0(Drive *d, void *id)
1136 {
1137         Aprdt *p;
1138         Cmd *x;
1139         Cmdh *h;
1140
1141         x = d->cmd;
1142         identifyfis(d, x->cfis);
1143
1144         h = x->cmdh;
1145         memset(h, 0, 16);
1146         h->fislen[0] = 5;
1147         h->len[0] = 1;          /* one prdt entry */
1148
1149         memset(id, 0, 0x200);
1150         p = x;
1151         p->dba = PCIWADDR(id);
1152         p->dbahi = Pciwaddrh(id);
1153         p->count = 0x200;
1154
1155         return command(d, Dsata, 3*1000);
1156 }
1157
1158 static int
1159 identify(Drive *d)
1160 {
1161         int i, n;
1162         vlong osectors, s;
1163         uchar oserial[21];
1164         ushort *id;
1165         SDunit *u;
1166
1167         id = d->info;
1168         for(i = 0;; i++){
1169                 if(i > 5 || identify0(d, id) != 0)
1170                         return -1;
1171                 n = idpuis(id);
1172                 if(n & Pspinup && setfeatures(d, 7, 20*1000) == -1)
1173                         dprint("%s: puis spinup fail\n", dnam(d));
1174                 if(n & Pidready)
1175                         break;
1176         }
1177
1178         s = idfeat(d, id);
1179         if(s == -1)
1180                 return -1;
1181         if((d->feat&Dlba) == 0){
1182                 dprint("%s: no lba support\n", dnam(d));
1183                 return -1;
1184         }
1185         osectors = d->sectors;
1186         memmove(oserial, d->serial, sizeof d->serial);
1187
1188         d->sectors = s;
1189         d->secsize = idss(d, id);
1190
1191         idmove(d->serial, id+10, 20);
1192         idmove(d->firmware, id+23, 8);
1193         idmove(d->model, id+27, 40);
1194         d->wwn = idwwn(d, id);
1195
1196         u = d->unit;
1197         memset(u->inquiry, 0, sizeof u->inquiry);
1198         u->inquiry[2] = 2;
1199         u->inquiry[3] = 2;
1200         u->inquiry[4] = sizeof u->inquiry - 4;
1201         memmove(u->inquiry+8, d->model, 40);
1202
1203         if(osectors != s || memcmp(oserial, d->serial, sizeof oserial)){
1204                 d->drivechange = 1;
1205                 u->sectors = 0;
1206         }
1207         return 0;
1208 }
1209
1210 /* open address fises */
1211 enum{
1212         Initiator               = 0x80,
1213         Openaddr        = 1,
1214         Awms            = 0x8000,
1215         Smp             = 0,
1216         Ssp             = 1,
1217         Stp             = 2,
1218         Spd15           = 8,
1219         Spd30           = 9,
1220 };
1221
1222 static void
1223 oafis(Cfis *f, uchar *c, int type)
1224 {
1225         c[0] = Initiator | type<<4 | Openaddr;
1226         c[1] = Spd30;                           /* botch; just try 3gbps */
1227         if(type == Smp)
1228                 memset(c + 2, 0xff, 2);
1229         else
1230                 memmove(c + 2, f->ict, 2);
1231         memmove(c + 4, f->tsasaddr, 8);         /* dest "port identifier" §4.2.6 */
1232         memmove(c + 12, f->ssasaddr, 8);
1233 }
1234
1235 /* sas fises */
1236 static int
1237 sasfis(Cfis*, uchar *c, SDreq *r)
1238 {
1239         memmove(c, r->cmd, r->clen);
1240         if(r->clen < 16)
1241                 memset(c + r->clen, 0, 16 - r->clen);
1242         return 0;
1243 }
1244
1245 /* sam3 §4.9.4 single-level lun structure */
1246 static void
1247 scsilun8(uchar *c, int l)
1248 {
1249         memset(c, 0, 8);
1250         if(l < 255)
1251                 c[1] = l;
1252         else if(l < 16384){
1253                 c[0] = 1<<6 | l>>8;
1254                 c[1] = l;
1255         }else
1256                 print("bad lun %d\n", l);
1257 }
1258
1259 static void
1260 iuhdr(SDreq *r, uchar *c, int fburst)
1261 {
1262         scsilun8(c, r->lun);
1263         c[8] = 0;
1264         c[9] = 0;
1265         if(fburst)
1266                 c[9] = 0x80;
1267 }
1268
1269 static void
1270 ssphdr(Cfis *x, uchar *c, int ftype)
1271 {
1272         memset(c, 0, 0x18);
1273         c[0] = ftype;
1274         sasbhash(c + 1, x->tsasaddr);
1275         sasbhash(c + 5, x->ssasaddr);
1276 }
1277
1278 /* debugging */
1279 static void
1280 dump(uchar *u, uint n)
1281 {
1282         uint i;
1283
1284         if(n > 100)
1285                 n = 100;
1286         for(i = 0; i < n; i += 4){
1287                 print("%.2d  %.2ux%.2ux%.2ux%.2ux", i, u[i], u[i + 1], u[i + 2], u[i + 3]);
1288                 print("\n");
1289         }
1290 }
1291
1292 static void
1293 prsense(uchar *u, uint n)
1294 {
1295         print("sense data %d: \n", n);
1296         dump(u, n);
1297 }
1298
1299 static void
1300 priu(uchar *u, uint n)
1301 {
1302         print("iu %d: \n", n);
1303         dump(u, n);
1304 }
1305
1306 /*
1307  * other suspects:
1308  * key  asc/q
1309  * 02   0401    becoming ready
1310  *      040b    target port in standby state
1311  *      0b01    overtemp
1312  *      0b0[345]        background *
1313  *      0c01    write error - recovered with auto reallocation
1314  *      0c02    write error - auto reallocation failed
1315  *      0c03    write error - recommend reassignment
1316  *      17*     recovered data
1317  *      18*     recovered data
1318  *      5d*     smart-style reporting (disk/smart handles)
1319  *      5e*     power state change
1320  */
1321
1322 static int
1323 classifykey(int asckey)
1324 {
1325         if(asckey == 0x062901 || asckey == 0x062900){
1326                 /* power on */
1327                 dprint("power on sense\n");
1328                 return SDretry;
1329         }
1330         return SDcheck;
1331 }
1332
1333 /* spc3 §4.5 */
1334 static int
1335 sasrspck(Drive *d, SDreq *r, int min)
1336 {
1337         char *p;
1338         int rv;
1339         uchar *u, *s;
1340         uint l, fmt, n, keyasc;
1341
1342         u = d->cmd->rsp;
1343         s = u + 24;
1344         dprint("status %d datapres %d\n", u[11], u[10]);
1345         switch(u[10]){
1346         case 1:
1347                 l = getbe(u + 20, 4);
1348                 /*
1349                  * this is always a bug because we don't do
1350                  * task mgmt
1351                  */
1352                 print("%s: bug: task data %d min %d\n", dnam(d), l, min);
1353                 return SDcheck;
1354         case 2:
1355                 l = getbe(u + 16, 4);
1356                 n = sizeof r->sense;
1357                 if(l < n)
1358                         n = l;
1359                 memmove(r->sense, s, n);
1360                 fmt = s[0] & 0x7f;
1361                 keyasc = (s[2] & 0xf)<<16 | s[12]<<8 | s[13];
1362                 rv = SDcheck;
1363                 /* spc3 §4.5.3; 0x71 is deferred. */
1364                 if(n >= 18 && (fmt == 0x70 || fmt == 0x71)){
1365                         rv = classifykey(keyasc);
1366                         p = "";
1367                         if(rv == SDcheck){
1368                                 r->flags |= SDvalidsense;
1369                                 p = "valid";
1370                         }
1371                         dprint("sense %.6ux %s\n", keyasc, p);
1372                 }else
1373                         prsense(s, l);
1374                 return rv;
1375         default:
1376                 print("%s: sasrspck: spurious\n", dnam(d));
1377                 priu(u, 24);
1378                 prsense(s, 0x30);
1379                 return SDcheck;
1380         }
1381 }
1382
1383 static int
1384 buildsas(Drive *d, SDreq *r, uchar *data, int n)
1385 {
1386         int w, try, fburst;
1387         Aprdt *p;
1388         Cmd *x;
1389         Cmdh *h;
1390
1391         try = 0;
1392 top:
1393         fburst = 0;             /* Firstburst? */
1394         x = d->cmd;
1395         /* ssphdr(d, x->sspfh, 6); */
1396         iuhdr(r, x->sasiu, fburst);
1397         w = 0;
1398         if(r->clen > 16)
1399                 w = r->clen - 16 + 3>> 2;
1400         x->sasiu[11] = w;
1401         sasfis(d, x->sasiu + 12, r);
1402
1403         h = x->cmdh;
1404         memset(h, 0, 16);
1405         h->sasctl = Tlretry | /*Vrfylen |*/ Sspcmd | fburst;
1406         h->fislen[0] = sizeof x->sspfh + 12 + 16 + 4*w >> 2;
1407         h->maxrsp = 0xff;
1408         if(n)
1409                 h->len[0] = 1;
1410         h->ttag[0] = 1;
1411         *(uint*)h->dlen = n;
1412
1413         if(n){
1414                 p = x;
1415                 p->dba = PCIWADDR(data);
1416                 p->dbahi = Pciwaddrh(data);
1417                 p->count = n;
1418         }
1419         switch(w = command(d, Dssp, 10*1000)){
1420         case 0:
1421                 r->status = sdsetsense(r, SDok, 0, 0, 0);
1422                 return 0;
1423         case Response | Done | Active:
1424                 r->status = sasrspck(d, r, 0);
1425                 if(r->status == SDok)
1426                         return 0;
1427                 if(r->status == SDretry){
1428                         if(try++ < 2)
1429                                 goto top;
1430                         r->status |= SDvalidsense;
1431                 }
1432                 return w | Sense;
1433         default:
1434                 r->status = sdsetsense(r, SDcheck, 4, 24, 0);
1435                 return w;
1436         }
1437 }
1438
1439 static uint
1440 analyze(Drive *d, Statb *b)
1441 {
1442         uint u, r, t;
1443
1444         r = 0;
1445         u = *(uint*)b->error;
1446         if(u & Eissuestp){
1447                 r |= Error;
1448                 unsetci(d);
1449         }
1450         if(u & Etask && (d->feat & Datapi) == 0){
1451                 t = gettask(d);
1452                 if(t & 1)
1453                         tprint(d, t);
1454                 if(t & Efatal<<8 || t & (ASbsy|ASdrq))
1455                         r |= Noverdict|Atareset;
1456                 if(t&Adhrs && t&33)
1457                         r |= Noverdict|Atareset;
1458                 else
1459                         r |= Error;
1460         }
1461         if(u & (Ererr | Ebadprot)){
1462                 /* sas thing */
1463                 print("%s: sas error %.8ux\n", dnam(d), u);
1464                 r |= Error;
1465         }
1466         if(u & ~(Ebadprot | Ererr | Etask | Eissuestp))
1467                 print("%s: analyze %.8ux\n", dnam(d), u);
1468
1469         return r;
1470 }
1471
1472 static void
1473 updatedone(Ctlr *c)
1474 {
1475         uint a, e, i, u, slot;
1476         Cmd *x;
1477         Drive *d;
1478
1479         e = c->cq[0];
1480         if(e == 0xfff)
1481                 return;
1482         if(e > Qmask)
1483                 print("sdodin: bug: bad cqrp %ux\n", e);
1484         e = e+1 & Qmask;
1485         for(i = c->cqrp; i != e; i = i+1 & Qmask){
1486                 u = c->cq[1 + i];
1487                 c->cq[1 + i] = 0;
1488                 slot = u & 0xfff;
1489                 u &= ~slot;
1490                 d = c->drive + slot;
1491                 x = d->cmd;
1492                 if(u & Cqdone){
1493                         x->cflag |= Done;
1494                         u &= ~Cqdone;
1495                 }
1496                 if(u & (Crxfr | Cgood)){
1497                         if((u & Cgood) == 0)
1498                                 x->cflag |= Response;
1499                         u &= ~(Crxfr | Cgood);
1500                 }
1501                 if(u & Cerr){
1502                         dprint("%s: Cerr ..\n", dnam(d));
1503                         a = analyze(d, x);
1504                         x->cflag |= Done | a;
1505                         u &= ~Cerr;
1506                 }
1507                 if(x->cflag & Done)
1508                         wakeup(x);
1509                 if(u)
1510                         print("%s: odd bits %.8ux\n", dnam(d), u);
1511         }
1512 if(i == c->cqrp)print("odin: spur done\n");
1513         c->cqrp = i;
1514 }
1515
1516 static void
1517 updatedrive(Drive *d)
1518 {
1519         uint cause, s0, ewake;
1520         char *name;
1521         Cmd *x;
1522         static uint last, tk;
1523
1524         ewake = 0;
1525         cause = d->ctlr->reg[pis[d->driveno]];
1526         d->ctlr->reg[pis[d->driveno]] = cause;
1527         x = d->cmd;
1528         name = dnam(d);
1529
1530         if(last != cause || Ticks - tk > 5*1000){
1531                 dprint("%s: ca %ux ta %ux\n", name, cause, gettask(d));
1532                 tk = Ticks;
1533         }
1534         if(cause & (Phyunrdy | Phyidto | Pisataup | Pisasup)){
1535                 s0 = d->state;
1536                 if(cause == (Phyrdy | Comw)){
1537                         d->type = 0;
1538                         d->state = Dnopower;
1539                 }
1540                 switch(cause & (Phyunrdy | Phyidto | Phyidok | Sigrx)){
1541                 case Phyunrdy:
1542                         d->state = Dmissing;
1543                         if(sstatus(d) & Sphyrdy){
1544                                 if(d->type != 0)
1545                                         d->state = Dnew;
1546                                 else
1547                                         d->state = Dreset;
1548                         }
1549                         break;
1550                 case Phyidto:
1551                         d->type = 0;
1552                         d->state = Dmissing;
1553                         break;
1554                 case Phyidok:
1555                         d->type = Sas;
1556                         d->state = Dnew;
1557                         break;
1558                 case Sigrx:
1559                         d->type = Sata;
1560                         d->state = Dnew;
1561                         break;
1562                 }
1563                 dprint("%s: %s → %s [Apcrs] %s %ux\n", name, dstate(s0),
1564                         dstate(d->state), type[d->type], sstatus(d));
1565                 if(s0 == Dready && d->state != Dready)
1566                         idprint("%s: pulled\n", name);
1567                 if(d->state != Dready || ci(d))
1568                         ewake |= Done | Noverdict;
1569         }else if(cause & Piburp)
1570                 ewake |= Done | Noverdict;
1571         else if(cause & Pireset)
1572                 ewake |= Done | Noverdict | Creset;
1573         else if(cause & Piunsupp){
1574                 print("%s: unsupported h/w: %.8ux\n", name, cause);
1575                 ewake |= Done | Error;
1576                 d->type = 0;
1577                 d->state = Doffline;
1578         }
1579         if(ewake){
1580                 dprint("%s: ewake %.8ux\n", name, ewake);
1581                 unsetci(d);
1582                 x->cflag |= ewake;
1583                 wakeup(x);
1584         }
1585         last = cause;
1586 }
1587
1588 static int
1589 satareset(Drive *d)
1590 {
1591         ilock(d->ctlr);
1592         unsetci(d);
1593         iunlock(d->ctlr);
1594         if(gettask(d) & (ASdrq|ASbsy))
1595                 return -1;
1596         if(settxmode(d, d->udma) != 0)
1597                 return -1;
1598         return 0;
1599 }
1600
1601 static int
1602 msriopkt(SDreq *r, Drive *d)
1603 {
1604         int n, count, try, max, flag, task;
1605         uchar *cmd;
1606
1607         cmd = r->cmd;
1608         aprint("%02ux %02ux %c %d %p\n", cmd[0], cmd[2], "rw"[r->write],
1609                 r->dlen, r->data);
1610         r->rlen = 0;
1611         count = r->dlen;
1612         max = 65536;
1613
1614         for(try = 0; try < 10; try++){
1615                 n = count;
1616                 if(n > max)
1617                         n = max;
1618                 if(lockready(d) == -1)
1619                         return SDeio;
1620                 flag = buildpkt(d, r, r->data, n);
1621                 task = gettask(d);
1622                 if(flag & Atareset && satareset(d) == -1)
1623                         setstate(d, Dreset);
1624                 qunlock(d);
1625                 if(flag & Noverdict){
1626                         if(flag & Creset)
1627                                 setstate(d, Dreset);
1628                         print("%s: retry\n", dnam(d));
1629                         continue;
1630                 }
1631                 if(flag & Error){
1632                         if((task & Eidnf) == 0)
1633                                 print("%s: i/o error %ux\n", dnam(d), task);
1634                         return r->status = SDcheck;
1635                 }
1636                 return r->status = SDok;
1637         }
1638         print("%s: bad disk\n", dnam(d));
1639         return r->status = SDcheck;
1640 }
1641
1642 static int
1643 msriosas(SDreq *r, Drive *d)
1644 {
1645         int try, flag;
1646
1647         for(try = 0; try < 10; try++){
1648                 if(lockready(d) == -1)
1649                         return SDeio;
1650                 flag = buildsas(d, r, r->data, r->dlen);
1651                 qunlock(d);
1652                 if(flag & Noverdict){
1653                         if(flag & Creset)
1654                                 setstate(d, Dreset);
1655                         print("%s: retry\n", dnam(d));
1656                         continue;
1657                 }
1658                 if(flag & Error){
1659                         print("%s: i/o error\n", dnam(d));
1660                         return r->status = SDcheck;
1661                 }
1662                 r->rlen = r->dlen;      /* fishy */
1663                 return r->status;               /* set in sasrspck */
1664
1665         }
1666         print("%s: bad disk\n", dnam(d));
1667         sdsetsense(r, SDcheck, 3, r->write? 0xc00: 0x11, 0);
1668         return r->status = SDcheck;
1669 }
1670
1671 static int
1672 flushcache(Drive *d)
1673 {
1674         int i;
1675
1676         i = -1;
1677         if(lockready(d) == 0)
1678                 i = mvflushcache(d);
1679         qunlock(d);
1680         return i;
1681 }
1682
1683 static int
1684 msriosata(SDreq *r, Drive *d)
1685 {
1686         char *name;
1687         int i, n, count, try, max, flag, task;
1688         uvlong lba;
1689         uchar *cmd, *data;
1690         SDunit *unit;
1691
1692         unit = r->unit;
1693         cmd = r->cmd;
1694         name = dnam(d);
1695
1696         if(cmd[0] == 0x35 || cmd[0] == 0x91){
1697                 if(flushcache(d) == 0)
1698                         return sdsetsense(r, SDok, 0, 0, 0);
1699                 return sdsetsense(r, SDcheck, 3, 0xc, 2);
1700         }
1701         if((i = sdfakescsi(r)) != SDnostatus){
1702                 r->status = i;
1703                 return i;
1704         }
1705         if((i = sdfakescsirw(r, &lba, &count, nil)) != SDnostatus)
1706                 return i;
1707         max = 128;
1708         if(d->feat & Dllba)
1709                 max = 65536;
1710         try = 0;
1711         data = r->data;
1712         while(count > 0){
1713                 n = count;
1714                 if(n > max)
1715                         n = max;
1716                 if(lockready(d) == -1)
1717                         return SDeio;
1718                 flag = build(d, r->write, data, n, lba);
1719                 task = gettask(d);
1720                 if(flag & Atareset && satareset(d) == -1)
1721                         setstate(d, Dreset);
1722                 qunlock(d);
1723                 if(flag & Noverdict){
1724                         if(flag & Creset)
1725                                 setstate(d, Dreset);
1726                         if(++try == 2){
1727                                 print("%s: bad disk\n", name);
1728                                 return r->status = SDeio;
1729                         }
1730                         iprint("%s: retry %lld [%.8ux]\n", name, lba, task);
1731                         continue;
1732                 }
1733                 if(flag & Error){
1734                         iprint("%s: i/o error %ux @%,lld\n", name, task, lba);
1735                         return r->status = SDeio;
1736                 }
1737                 count -= n;
1738                 lba   += n;
1739                 data += n*unit->secsize;
1740         }
1741         r->rlen = data - (uchar*)r->data;
1742         r->status = SDok;
1743         return SDok;
1744 }
1745
1746 static int
1747 msrio(SDreq *r)
1748 {
1749         Ctlr *c;
1750         Drive *d;
1751         SDunit *u;
1752
1753         u = r->unit;
1754         c = u->dev->ctlr;
1755         d = c->drive + u->subno;
1756         if(d->feat & Datapi)
1757                 return msriopkt(r, d);
1758         if(d->type == Sas)
1759                 return msriosas(r, d);
1760         if(d->type == Sata)
1761                 return msriosata(r, d);
1762         return sdsetsense(r, SDcheck, 3, 0x04, 0x24);
1763 }
1764
1765 /*
1766  * §6.1.9.5
1767  * not clear that this is necessary
1768  * we should know that it's a d2h from the status.
1769  * pio returns pio setup fises.  hw bug?
1770  */
1771 static int
1772 sdr(SDreq *r, Drive *d, int st)
1773 {
1774         uint i;
1775
1776         if(i = fisoffset(d, 0/*Rd2h*/))
1777                 memmove(r->cmd, d->ctlr->fis + i, 16);
1778         else
1779                 memset(r->cmd, 0xff, 16);
1780         r->status = st;
1781         return st;
1782 }
1783
1784 /*
1785  * handle oob requests;
1786  *    restrict & sanitize commands
1787  */
1788 static int
1789 fisreqchk(Sfis *f, SDreq *r)
1790 {
1791         uchar *c;
1792
1793         if((r->ataproto & Pprotom) == Ppkt)
1794                 return SDnostatus;
1795         if(r->clen != 16)
1796                 error("bad command length"); //error(Eio);
1797         c = r->cmd;
1798         if(c[0] == 0xf0){
1799                 sigtofis(f, r->cmd);
1800                 return r->status = SDok;
1801         }
1802         c[0] = H2dev;
1803         c[1] = Fiscmd;
1804         c[7] |= Ataobs;
1805         return SDnostatus;
1806 }
1807
1808 static int
1809 msataio(SDreq *r)
1810 {
1811         char *name;
1812         int try, flag, task;
1813         Ctlr *c;
1814         Drive *d;
1815         SDunit *u;
1816         int (*build)(Drive*, SDreq*, void*, int);
1817
1818         u = r->unit;
1819         c = u->dev->ctlr;
1820         d = c->drive + u->subno;
1821         name = dnam(d);
1822
1823         if(d->type != Sata)
1824                 error("not sata");
1825         if(r->cmd[0] == 0xf1){
1826                 d->state = Dreset;
1827                 return r->status = SDok;
1828         }
1829         if((r->status = fisreqchk(d, r)) != SDnostatus)
1830                 return r->status;
1831         build = buildfis;
1832         if((r->ataproto & Pprotom) == Ppkt)
1833                 build = buildpkt;
1834
1835         for(try = 0; try < 10; try++){
1836                 if(lockready(d) == -1)
1837                         return SDeio;
1838                 flag = build(d, r, r->data, r->dlen);
1839                 task = gettask(d);
1840                 if(flag & Atareset && satareset(d) == -1)
1841                         setstate(d, Dreset);
1842                 qunlock(d);
1843                 if(flag & Noverdict){
1844                         if(flag & (Timeout | Creset))
1845                                 setstate(d, Dreset);
1846                         else if(task & Eabrt<<8){
1847                                 /* assume bad cmd */
1848                                 r->status = SDeio;
1849                                 return SDeio;
1850                         }
1851                         print("%s: retry\n", name);
1852                         continue;
1853                 }
1854                 if(flag & Error){
1855                         print("%s: i/o error %.8ux\n", name, task);
1856                         r->status = SDeio;
1857                         return SDeio;
1858                 }
1859                 if(build != buildpkt)
1860                         r->rlen = r->dlen;
1861                 return sdr(r, d, SDok);
1862         }
1863         print("%s: bad disk\n", name);
1864         return sdr(r, d, SDeio);
1865 }
1866
1867 static void
1868 msinterrupt(Ureg *, void *a)
1869 {
1870         Ctlr *c;
1871         uint u, i;
1872         static uint cnt;
1873
1874         c = a;
1875         ilock(c);
1876         u = c->reg[Cis];
1877         if(u == 0){
1878                 iunlock(c);
1879                 return;
1880         }
1881         c->reg[Cis] = u & ~Iclr;
1882         if(u != Cdone && cnt++ < 15)
1883                 print("sdodin: irq %s %.8ux\n", c->sdev->ifc->name, u);
1884         for(i = 0; i < 8; i++)
1885                 if(u & (1<<i)*(Portirq|Portstop))
1886                         updatedrive(c->drive + i);
1887         if(u & Srsirq){
1888                 u = c->reg[Csis];
1889                 c->reg[Csis] = u;
1890                 for(i = 0; i < 8; i++)
1891                         if(u & 1<<i)
1892                                 updatedrive(c->drive + i);
1893         }
1894         if(u & Cdone){
1895                 updatedone(c);
1896                 c->reg[Cis] = Cdone;
1897         }
1898         iunlock(c);
1899 }
1900
1901 static char*
1902 mc(Drive *d)
1903 {
1904         char *s;
1905
1906         s = "";
1907         if(d->drivechange)
1908                 s = "[newdrive]";
1909         return s;
1910 }
1911
1912 static int
1913 newsatadrive(Drive *d)
1914 {
1915         uint task;
1916
1917         task = gettask(d);
1918         if((task & 0xffff) == 0x80)
1919                 return SDretry;
1920         setfissig(d, getsig(d));
1921         if(identify(d) != 0){
1922                 dprint("%s: identify failure\n", dnam(d));
1923                 return SDeio;
1924         }
1925         if(d->feat & Dpower && setfeatures(d, 0x85, 3*1000)  != 0){
1926                 d->feat &= ~Dpower;
1927                 if(satareset(d) == -1)
1928                         return SDeio;
1929         }
1930         if(settxmode(d, d->udma)  != 0){
1931                 dprint("%s: can't set tx mode\n", dnam(d));
1932                 return SDeio;
1933         }
1934         return SDok;
1935 }
1936
1937 static void
1938 newoaf(Drive *d, int type)
1939 {
1940         uint ict, i;
1941         uvlong sa;
1942         Ctlr *c;
1943
1944         i = d->driveno;
1945         c = d->ctlr;
1946
1947         sa = pcread(c, i, Pawwn + 0);
1948         sa |= (uvlong)pcread(c, i, Pawwn + 4)<<32;
1949         putbe(d->tsasaddr, sa, 8);
1950         memmove(d->ssasaddr, d->ssasaddr, 8);
1951         ict = pcread(c, i, Pwwn + 8);
1952         putbe(d->ict, ict, 2);
1953         oafis(d, d->cmd->oaf, type);
1954 }
1955
1956 static int
1957 sasinquiry(Drive *d)
1958 {
1959         SDreq r;
1960         SDunit *u;
1961
1962         u = d->unit;
1963         memset(&r, 0, sizeof r);
1964         r.cmd[0] = 0x12;
1965         r.cmd[4] = 0xff;
1966         r.clen = 6;
1967         r.unit = u;
1968
1969         return buildsas(d, &r, u->inquiry, sizeof u->inquiry);
1970 }
1971
1972 static int
1973 sastur(Drive *d)
1974 {
1975         SDreq r;
1976         SDunit *u;
1977
1978         u = d->unit;
1979         memset(&r, 0, sizeof r);
1980         r.clen = 6;
1981         r.unit = u;
1982         return buildsas(d, &r, 0, 0);
1983 }
1984
1985 static int
1986 sasvpd(Drive *d, uchar *buf, int l)
1987 {
1988         SDreq r;
1989         SDunit *u;
1990
1991         u = d->unit;
1992         memset(&r, 0, sizeof r);
1993         r.cmd[0] = 0x12;
1994         r.cmd[1] = 1;
1995         r.cmd[2] = 0x80;
1996         r.cmd[4] = l;
1997         r.clen = 6;
1998         r.unit = u;
1999         return buildsas(d, &r, buf, l);
2000 }
2001
2002 static int
2003 sascapacity10(Drive *d, uchar *buf, int l)
2004 {
2005         SDreq r;
2006         SDunit *u;
2007
2008         u = d->unit;
2009         memset(&r, 0, sizeof r);
2010         r.cmd[0] = 0x25;
2011         r.clen = 10;
2012         r.unit = u;
2013         return buildsas(d, &r, buf, l);
2014 }
2015
2016 static int
2017 sascapacity16(Drive *d, uchar *buf, int l)
2018 {
2019         SDreq r;
2020         SDunit *u;
2021
2022         u = d->unit;
2023         memset(&r, 0, sizeof r);
2024         r.cmd[0] = 0x9e;
2025         r.cmd[1] = 0x10;
2026         r.cmd[13] = l;
2027         r.clen = 16;
2028         r.unit = u;
2029         return buildsas(d, &r, buf, l);
2030 }
2031
2032 static void
2033 frmove(char *p, uchar *c, int n)
2034 {
2035         char *op, *e;
2036
2037         memmove(p, c, n);
2038         op = p;
2039         p[n] = 0;
2040         for(p = p + n - 1; p > op && *p == ' '; p--)
2041                 *p = 0;
2042         e = p;
2043         p = op;
2044         while(*p == ' ')
2045                 p++;
2046         memmove(op, p, n - (e - p));
2047 }
2048
2049 static void
2050 chkinquiry(Drive *d, uchar *c)
2051 {
2052         char buf[32], buf2[32], omod[sizeof d->model];
2053
2054         memmove(omod, d->model, sizeof d->model);
2055         frmove(buf, c + 8, 8);
2056         frmove(buf2, c + 16, 16);
2057         snprint(d->model, sizeof d->model, "%s %s", buf, buf2);
2058         frmove(d->firmware, c + 23, 4);
2059         if(memcmp(omod, d->model, sizeof omod) != 0)
2060                 d->drivechange = 1;
2061 }
2062
2063 static void
2064 chkvpd(Drive *d, uchar *c, int n)
2065 {
2066         char buf[sizeof d->serial];
2067         int l;
2068
2069         l = c[3];
2070         if(l > n)
2071                 l = n;
2072         frmove(buf, c + 4, l);
2073         if(strcmp(buf, d->serial) != 0)
2074                 d->drivechange = 1;
2075         memmove(d->serial, buf, sizeof buf);
2076 }
2077
2078 static int
2079 adjcapacity(Drive *d, uvlong ns, uint nss)
2080 {
2081         if(ns != 0)
2082                 ns++;
2083         if(nss == 2352)
2084                 nss = 2048;
2085         if(d->sectors != ns || d->secsize != nss){
2086                 d->drivechange = 1;
2087                 d->sectors = ns;
2088                 d->secsize = nss;
2089         }
2090         return 0;
2091 }
2092
2093 static int
2094 chkcapacity10(uchar *p, uvlong *ns, uint *nss)
2095 {
2096         *ns = getbe(p, 4);
2097         *nss = getbe(p + 4, 4);
2098         return 0;
2099 }
2100
2101 static int
2102 chkcapacity16(uchar *p, uvlong *ns, uint *nss)
2103 {
2104         *ns = getbe(p, 8);
2105         *nss = getbe(p + 8, 4);
2106         return 0;
2107 }
2108
2109 static int
2110 sasprobe(Drive *d)
2111 {
2112         uchar buf[0x40];
2113         int r;
2114         uint nss;
2115         uvlong ns;
2116
2117         if((r = sastur(d)) != 0)
2118                 return r;
2119         if((r = sasinquiry(d)) != 0)
2120                 return r;
2121         chkinquiry(d, d->unit->inquiry);
2122         /* vpd 0x80 (unit serial) is not mandatory */
2123         if((r = sasvpd(d, buf, sizeof buf)) == 0)
2124                 chkvpd(d, buf, sizeof buf);
2125         else if(r & (Error | Timeout))
2126                 return r;
2127         else{
2128                 if(d->serial[0])
2129                         d->drivechange = 1;
2130                 d->serial[0] = 0;
2131         }
2132         if((r = sascapacity10(d, buf, sizeof buf)) != 0)
2133                 return r;
2134         chkcapacity10(buf, &ns, &nss);
2135         if(ns == 0xffffffff){
2136                 if((r = sascapacity16(d, buf, sizeof buf)) != 0)
2137                         return r;
2138                 chkcapacity16(buf, &ns, &nss);
2139         }
2140         adjcapacity(d, ns, nss);
2141
2142         return 0;
2143 }
2144
2145 static int
2146 newsasdrive(Drive *d)
2147 {
2148         memset(d->cmd->rsp, 0, sizeof d->cmd->rsp);
2149         newoaf(d, Ssp);
2150         switch(sasprobe(d) & (Error | Noverdict | Timeout | Sense)){
2151         case Error:
2152         case Timeout:
2153                 return SDeio;
2154         case Sense:
2155         case Noverdict:
2156                 return SDretry;
2157         }
2158         return SDok;
2159 }
2160
2161 static int
2162 newdrive(Drive *d)
2163 {
2164         char *t;
2165         int r;
2166
2167         memset(&d->Sfis, 0, sizeof d->Sfis);
2168         memset(&d->Cfis, 0, sizeof d->Cfis);
2169         qlock(d);
2170         switch(d->type){
2171         case Sata:
2172                 r = newsatadrive(d);
2173                 break;
2174         case Sas:
2175                 r = newsasdrive(d);
2176                 break;
2177         default:
2178                 print("%s: bug: martian drive %d\n", dnam(d), d->type);
2179                 qunlock(d);
2180                 return -1;
2181         }
2182         t = type[d->type];
2183         switch(r){
2184         case SDok:
2185                 idprint("%s: %s %,lld sectors\n", dnam(d), t, d->sectors);
2186                 idprint("  %s %s %s %s\n", d->model, d->firmware, d->serial, mc(d));
2187                 setstate(d, Dready);
2188                 break;
2189         case SDeio:
2190                 idprint("%s: %s can't be initialized\n", dnam(d), t);
2191                 setstate(d, Derror);
2192         case SDretry:
2193                 break;
2194         }
2195         qunlock(d);
2196         return r;
2197 }
2198
2199 static void
2200 statechange(Drive *d)
2201 {
2202         switch(d->state){
2203         case Dmissing:
2204         case Dnull:
2205         case Doffline:
2206                 d->drivechange = 1;
2207                 d->unit->sectors = 0;
2208                 break;
2209         case Dready:
2210                 d->wait = 0;
2211                 break;
2212         }
2213 }
2214
2215 /*
2216  * we don't respect running commands.  botch?
2217  */
2218 static void
2219 checkdrive(Drive *d, int i)
2220 {
2221         uint s;
2222
2223         if(d->unit == nil)
2224                 return;
2225         ilock(d);
2226         s = sstatus(d);
2227         d->wait++;
2228         if(s & Sphyrdy)
2229                 d->lastseen = Ticks;
2230         if(s != olds[i]){
2231                 dprint("%s: status: %.6ux -> %.6ux: %s\n",
2232                         dnam(d), olds[i], s, dstate(d->state));
2233                 olds[i] = s;
2234                 statechange(d);
2235         }
2236         switch(d->state){
2237         case Dnull:
2238         case Dmissing:
2239                 if(d->type != 0 && s & Sphyrdy)
2240                         d->state = Dnew;
2241                 break;
2242         case Dnopower:
2243                 phyreset(d);    /* spinup */
2244                 break;
2245         case Dnew:
2246                 if(d->wait % 6 != 0)
2247                         break;
2248                 iunlock(d);
2249                 newdrive(d);
2250                 ilock(d);
2251                 break;
2252         case Dready:
2253                 d->wait = 0;
2254                 break;
2255         case Derror:
2256                 d->wait = 0;
2257                 d->state = Dreset;
2258         case Dreset:
2259                 if(d->wait % 40 != 0)
2260                         break;
2261                 reset(d);
2262                 break;
2263         case Doffline:
2264         case Dportreset:
2265                 break;
2266         }
2267         iunlock(d);
2268 }
2269
2270 static void
2271 mskproc(void*)
2272 {
2273         int i;
2274
2275         for(;;){
2276                 tsleep(&up->sleep, return0, 0, Nms);
2277                 for(i = 0; i < nmsdrive; i++)
2278                         checkdrive(msdrive[i], i);
2279         }
2280 }
2281
2282 static void
2283 ledcfg(Ctlr *c, int port, uint cfg)
2284 {
2285         uint u, r, s;
2286
2287         r = Drivectl + (port>>2)*Gpiooff;
2288         s = 15 - port & 3;
2289         s *= 8;
2290         u = gpread(c, r);
2291         u &= ~(0xff << s);
2292         u |= cfg<<s;
2293         gpwrite(c, r, u);
2294 }
2295
2296 static uchar ses2ledstd[Ibpilast] = {
2297 [Ibpinone]      Lhigh*Aled,
2298 [Ibpinormal]    Lsof*Aled | Llow*Locled | Llow*Errled,
2299 [Ibpirebuild]   Lsof*Aled | Llow*Locled | Llow*Errled,
2300 [Ibpilocate]    Lsof*Aled | Lblinka*Locled | Llow*Errled,
2301 [Ibpispare]     Lsof*Aled | Llow*Locled| Lblinka*Errled,
2302 [Ibpipfa]               Lsof*Aled | Lblinkb*Locled | Llow*Errled,
2303 [Ibpifail]              Lsof*Aled | Llow*Locled | Lhigh*Errled,
2304 [Ibpicritarray] Lsof*Aled,
2305 [Ibpifailarray] Lsof*Aled,
2306 };
2307
2308 static uchar ses2led[Ibpilast] = {
2309 [Ibpinone]      Lhigh*Aled,
2310 [Ibpinormal]    Lsof*Aled | Llow*Locled | Llow*Errled,
2311 [Ibpirebuild]   Lsof*Aled | Lblinkaneg*Locled | Llow*Errled,
2312 [Ibpilocate]    Lsof*Aled | Lhigh*Locled | Llow*Errled,
2313 [Ibpispare]     Lsof*Aled | Lblinka*Locled| Llow*Errled,
2314 [Ibpipfa]               Lsof*Aled | Lblinkb*Locled | Llow*Errled,
2315 [Ibpifail]              Lsof*Aled | Llow*Locled | Lhigh*Errled,
2316 [Ibpicritarray] Lsof*Aled,
2317 [Ibpifailarray] Lsof*Aled,
2318 };
2319
2320 static void
2321 setupled(Ctlr *c)
2322 {
2323         int i, l, blen;
2324         pcicfgw32(c->pci, Gpio, pcicfgr32(c->pci, Gpio) | 1<<7);
2325
2326         /*
2327          * configure a for 4hz (1/8s on and 1/8s off)
2328          * configure b for 1hz (2/8s on and 6/8s off)
2329          */
2330         l = 3 + c->ndrive >> 2;
2331         blen = 3*24 - 1;
2332         for(i = 0; i < l*Gpiooff; i += Gpiooff){
2333                 gpwrite(c, Sgconf0 + i, blen*Autolen | Blinkben | Blinkaen | Sgpioen);
2334                 gpwrite(c, Sgconf1 + i, 1*Bhi | 1*Blo | 1*Ahi | 7*Alo);
2335                 gpwrite(c, Sgconf3 + i, 7<<20 | Sdoutauto);
2336         }
2337 }
2338
2339 static void
2340 trebuild(Ctlr *c, Drive *d, int dno, uint i)
2341 {
2342         uchar bits;
2343
2344         if(0 && d->led == Ibpirebuild){
2345                 switch(i%19){
2346                 case 0:
2347                         bits = 0;
2348                         break;
2349                 case 1:
2350                         bits = ses2led[Ibpirebuild] | Lblinka*Locled;
2351                         break;
2352                 case 3:
2353                         bits = ses2led[Ibpirebuild] | Lblinkb*Locled;
2354                         break;
2355                 }
2356         }else
2357                 bits =  ses2led[d->led];
2358         if(d->ledbits != bits)
2359                 ledcfg(c, dno, bits);
2360 }
2361
2362 static long
2363 odinledr(SDunit *u, Chan *ch, void *a, long n, vlong off)
2364 {
2365         Ctlr *c;
2366         Drive *d;
2367
2368         c = u->dev->ctlr;
2369         d = c->drive + u->subno;
2370         return ledr(d, ch, a, n, off);
2371 }
2372
2373 static long
2374 odinledw(SDunit *u, Chan *ch, void *a, long n, vlong off)
2375 {
2376         Ctlr *c;
2377         Drive *d;
2378
2379         c = u->dev->ctlr;
2380         d = c->drive + u->subno;
2381         return ledw(d, ch, a, n, off);
2382 }
2383
2384 /*
2385  * this kproc can probablly go when i figure out
2386  * how to program the manual blinker
2387  */
2388 static void
2389 ledkproc(void*)
2390 {
2391         uint i, j;
2392         Drive *d;
2393
2394         for(i = 0; i < nmsdrive; i++){
2395                 d = msdrive[i];
2396                 d->nled = 2;            /* how to know? */
2397         }
2398         for(i = 0; i < nmsctlr; i++)
2399                 pcicfgw32(msctlr[i].pci, Gpio, pcicfgr32(msctlr[i].pci, Gpio) | 1<<7);
2400         for(i = 0; i < nmsctlr; i++)
2401                 setupled(msctlr + i);
2402         for(i = 0; ; i++){
2403                 esleep(Nms);
2404                 for(j = 0; j < nmsdrive; j++){
2405                         d = msdrive[j];
2406                         trebuild(d->ctlr, d, j, i);
2407                 }
2408         }
2409 }
2410
2411 static int
2412 msenable(SDev *s)
2413 {
2414         char buf[32];
2415         Ctlr *c;
2416         static int once;
2417
2418         c = s->ctlr;
2419         ilock(c);
2420         if(!c->enabled){
2421                 if(once++ == 0)
2422                         kproc("odin", mskproc, 0);
2423                 pcisetbme(c->pci);
2424                 snprint(buf, sizeof buf, "%s (%s)", s->name, s->ifc->name);
2425                 intrenable(c->pci->intl, msinterrupt, c, c->pci->tbdf, buf);
2426 //              c->reg[Cis] |= Swirq1;          /* force initial interrupt. */
2427                 c->enabled = 1;
2428         }
2429         iunlock(c);
2430         return 1;
2431 }
2432
2433 static int
2434 msdisable(SDev *s)
2435 {
2436         char buf[32];
2437         Ctlr *c;
2438
2439         c = s->ctlr;
2440         ilock(c);
2441 //      disable(c->hba);
2442         snprint(buf, sizeof buf, "%s (%s)", s->name, s->ifc->name);
2443         intrdisable(c->pci->intl, msinterrupt, c, c->pci->tbdf, buf);
2444         c->enabled = 0;
2445         iunlock(c);
2446         return 1;
2447 }
2448
2449 static int
2450 scsiish(Drive *d)
2451 {
2452         return d->type == Sas || d->feat & Datapi;
2453 }
2454
2455 static int
2456 msonline(SDunit *u)
2457 {
2458         int r;
2459         Ctlr *c;
2460         Drive *d;
2461
2462         c = u->dev->ctlr;
2463         d = c->drive + u->subno;
2464         r = 0;
2465
2466         if(scsiish(d)){
2467                 if(!d->drivechange)
2468                         return r;
2469                 r = scsionline(u);
2470                 if(r > 0)
2471                         d->drivechange = 0;
2472                 return r;
2473         }
2474         ilock(d);
2475         if(d->drivechange){
2476                 r = 2;
2477                 d->drivechange = 0;
2478                 u->sectors = d->sectors;
2479                 u->secsize = d->secsize;
2480         } else if(d->state == Dready)
2481                 r = 1;
2482         iunlock(d);
2483         return r;
2484 }
2485
2486 static void
2487 verifychk(Drive *d)
2488 {
2489         int w;
2490
2491         if(!up)
2492                 checkdrive(d, d->driveno);
2493         for(w = 0; w < 12000; w += 210){
2494                 if(d->state == Dready)
2495                         break;
2496                 if(w > 2000 && d->state != Dnew)
2497                         break;
2498                 if((sstatus(d) & Sphyrdy) == 0)
2499                         break;
2500                 if(!up)
2501                         checkdrive(d, d->driveno);
2502                 esleep(210);
2503         }
2504 }
2505
2506 static int
2507 msverify(SDunit *u)
2508 {
2509         int chk;
2510         Ctlr *c;
2511         Drive *d;
2512         static int once;
2513
2514         c = u->dev->ctlr;
2515         d = c->drive + u->subno;
2516         ilock(c);
2517         ilock(d);
2518         chk = 0;
2519         if(d->unit == nil){
2520                 d->unit = u;
2521                 sdaddfile(u, "led", 0644, eve, odinledr, odinledw);
2522                 once++;
2523                 if(once == nmsctlr)
2524                         kproc("mvled", ledkproc, 0);
2525                 chk = 1;
2526         }
2527         iunlock(d);
2528         iunlock(c);
2529
2530         /*
2531          * since devsd doesn't know much about hot-plug drives,
2532          * we need to give detected drives a chance.
2533          */
2534         if(chk){
2535                 reset(d);
2536                 verifychk(d);
2537         }
2538         return 1;
2539 }
2540
2541 static uint*
2542 map(Pcidev *p, int bar)
2543 {
2544         uintptr io;
2545
2546         io = p->mem[bar].bar & ~0xf;
2547         return (uint*)vmap(io, p->mem[bar].size);
2548 }
2549
2550 /* §5.1.3 */
2551 static void
2552 initmem(Ctlr *c)
2553 {
2554         c->fis = malloc(0x800 + 0x100*16);      /* §6.1.9.3 */
2555         c->cl = malloc(nelem(c->cq)*sizeof *c->cl);
2556         c->cmdtab = malloc(Nctlrdrv*sizeof *c->cmdtab);
2557         if(c->fis == nil || c->cl == nil || c->cmdtab == nil)
2558                 panic("sdodin: no memory");
2559         c->reg[Fisbase + 0] = PCIWADDR(c->fis);
2560         c->reg[Fisbase + 1] = Pciwaddrh(c->fis);
2561         c->reg[Cqbase + 0] = PCIWADDR(c->cq);
2562         c->reg[Cqbase + 1] = Pciwaddrh(c->cq);
2563         c->reg[Cqcfg] = Cqen | Noattn | nelem(c->cq) - 1;
2564         c->reg[Dqbase + 0] = PCIWADDR(c->dq);
2565         c->reg[Dqbase + 1] = Pciwaddrh(c->dq);
2566         c->reg[Dqcfg] = Dqen | nelem(c->dq);
2567         c->reg[Clbase + 0] = PCIWADDR(c->cl);
2568         c->reg[Clbase + 1] = Pciwaddrh(c->cl);
2569 }
2570
2571 /* §5.1.2 */
2572 static void
2573 startup(Ctlr *c)
2574 {
2575         c->reg[Gctl] |= Reset;
2576         while(c->reg[Gctl] & Reset)
2577                 ;
2578         initmem(c);
2579         c->reg[Cie] = Swirq1 | 0xff*Portstop | 0xff*Portirq | Srsirq | Issstop | Cdone;
2580         c->reg[Gctl] |= Intenable;
2581         c->reg[Portcfg0] = Rmask*Regen | Dataunke | Rsple | Framele;
2582         c->reg[Portcfg1] = Rmask*Regen | 0xff*Xmten | /*Cmdirq |*/ Fisen | Resetiss | Issueen;
2583         c->reg[Csie] = ~0;
2584         sswrite(c, 0, Pwdtimer, 0x7fffff);
2585 }
2586
2587 static void
2588 forcetype(Ctlr*)
2589 {
2590         /*
2591          * if we want to force sas/sata, here's where to do it.
2592          */
2593 }
2594
2595 static void
2596 setupcmd(Drive *d)
2597 {
2598         int i;
2599         Ctlr *c;
2600         Cmd *cmd;
2601         Cmdh *h;
2602
2603         i = d->driveno;
2604         c = d->ctlr;
2605         d->cmd = c->cmdtab + i;
2606         d->cmd->cmdh = c->cl + i;
2607         cmd = d->cmd;
2608         h = cmd->cmdh;
2609
2610         /* prep the precomputable bits in the cmd hdr §6.1.4 */
2611         putle(h->ctab, Pciw64(&cmd->Ctab), sizeof h->ctab);
2612         putle(h->oaf, Pciw64(&cmd->Oaf), sizeof h->oaf);
2613         putle(h->statb, Pciw64(&cmd->Statb), sizeof h->statb);
2614         putle(h->prd, Pciw64(&cmd->Aprdt), sizeof h->prd);
2615
2616         /* finally, set up the wide-port participating bit */
2617         pcwrite(c, i, Pwidecfg, 1<<i);
2618 }
2619
2620 static void
2621 phychk(Ctlr *c, Drive *d)
2622 {
2623         int i;
2624         uvlong u;
2625         static uchar src[8] = {0x50, 0x03, 0x04, 0x80};
2626
2627         i = d->driveno;
2628         memmove(d->ssasaddr, src, 8);
2629         u = getbe(d->ssasaddr, 8);
2630         pcwrite(c, i, Paddr + 0, u);
2631         pcwrite(c, i, Paddr + 4, u>>32);
2632 }
2633
2634 static SDev*
2635 mspnp(void)
2636 {
2637         int i, nunit;
2638         Ctlr *c;
2639         Drive *d;
2640         Pcidev *p;
2641         SDev **ll, *s, *s0;
2642         static int done;
2643
2644         if(done++)
2645                 return nil;
2646         s0 = nil;
2647         ll = &s0;
2648         for(p = nil; (p = pcimatch(p, 0x11ab, 0x6485)) != nil; ){
2649                 if(nmsctlr == Nctlr){
2650                         print("sdodin: too many controllers\n");
2651                         break;
2652                 }
2653                 c = msctlr + nmsctlr;
2654                 s = sdevs + nmsctlr;
2655                 memset(c, 0, sizeof *c);
2656                 memset(s, 0, sizeof *s);
2657                 if((c->reg = map(p, Mebar)) == 0){
2658                         print("sdodin: bar %#p in use\n", c->reg);
2659                         continue;
2660                 }
2661                 nunit = p->did>>4 & 0xf;
2662                 s->ifc = &sdodinifc;
2663                 s->idno = 'a' + nmsctlr;
2664                 s->ctlr = c;
2665                 c->sdev = s;
2666                 c->pci = p;
2667                 c->ndrive = s->nunit = nunit;
2668                 i = pcicfgr32(p, Dctl) & ~(7<<12);
2669                 pcicfgw32(p, Dctl, i | 4<<12);
2670
2671                 print("#S/sd%c: odin ii sata/sas with %d ports\n", s->idno, nunit);
2672                 startup(c);
2673                 forcetype(c);
2674                 for(i = 0; i < nunit; i++){
2675                         d = c->drive + i;
2676                         d->driveno = i;
2677                         d->sectors = 0;
2678                         d->ctlr = c;
2679                         setupcmd(d);
2680                         snprint(d->name, sizeof d->name, "odin%d.%d", nmsctlr, i);
2681                         msdrive[nmsdrive + i] = d;
2682 //                      phychk(c, d);
2683                         c->reg[pis[i] + 1] =
2684                                 Sync | Phyerr | Stperr | Crcerr |
2685                                 Linkrx | Martianfis | Anot | Bist | Sigrx |
2686                                 Phyunrdy | Martiantag | Bnot | Comw |
2687                                 Portsel | Hreset | Phyidto | Phyidok |
2688                                 Hresetok | Phyrdy;
2689                 }
2690                 nmsdrive += nunit;
2691                 nmsctlr++;
2692                 *ll = s;
2693                 ll = &s->next;
2694         }
2695         return s0;
2696 }
2697
2698 static char*
2699 msrctlsata(Drive *d, char *p, char *e)
2700 {
2701         p = seprint(p, e, "flag\t");
2702         p = pflag(p, e, d);
2703         p = seprint(p, e, "udma\t%d\n", d->udma);
2704         return p;
2705 }
2706
2707 static char*
2708 rctldebug(char *p, char *e, Ctlr *c, Drive *d)
2709 {
2710         int i;
2711         uvlong sasid;
2712
2713         i = d->driveno;
2714         p = seprint(p, e, "sstatus\t%.8ux\n", sstatus(d));
2715 //      p = seprint(p, e, "cis\t%.8ux %.8ux\n", c->reg[Cis], c->reg[Cie]);
2716 //      p = seprint(p, e, "gis\t%.8ux\n", c->reg[Gis]);
2717         p = seprint(p, e, "pis\t%.8ux %.8ux\n", c->reg[pis[i]], c->reg[pis[i] + 1]);
2718         p = seprint(p, e, "sis\t%.8ux\n", c->reg[Csis]);
2719         p = seprint(p, e, "cqwp\t%.8ux\n", c->cq[0]);
2720         p = seprint(p, e, "cerror\t%.8ux %.8ux\n", *(uint*)d->cmd->error, *(uint*)(d->cmd->error+4));
2721         p = seprint(p, e, "task\t%.8ux\n", gettask(d));
2722         p = seprint(p, e, "ptype\t%.8ux\n", c->reg[Ptype]);
2723         p = seprint(p, e, "satactl\t%.8ux\n", pcread(c, i, Psatactl));  /* appears worthless */
2724         p = seprint(p, e, "info %.8ux %.8ux\n", pcread(c, i, Pinfo), pcread(c, i, Painfo));
2725         p = seprint(p, e, "physts       %.8ux\n", pcread(c, i, Pphysts));
2726         p = seprint(p, e, "widecfg      %.8ux\n", pcread(c, i, Pwidecfg));
2727         sasid = pcread(c, i, Pwwn + 0);
2728         sasid |= (uvlong)pcread(c, i, Pwwn + 4)<<32;
2729         p = seprint(p, e, "wwn  %.16llux %.8ux\n", sasid, pcread(c, i, Pwwn + 8));
2730         sasid = pcread(c, i, Pawwn + 0);
2731         sasid |= (uvlong)pcread(c, i, Pawwn + 4)<<32;
2732         p = seprint(p, e, "awwn %.16llux\n", sasid);
2733         sasid = pcread(c, i, Paddr + 0);
2734         sasid |= (uvlong)pcread(c, i, Paddr + 4)<<32;
2735         p = seprint(p, e, "sasid        %.16llux\n", sasid);
2736         return p;
2737 }
2738
2739 static int
2740 msrctl(SDunit *u, char *p, int l)
2741 {
2742         char *e, *op;
2743         Ctlr *c;
2744         Drive *d;
2745
2746         if((c = u->dev->ctlr) == nil)
2747                 return 0;
2748         d = c->drive + u->subno;
2749         e = p + l;
2750         op = p;
2751         p = seprint(p, e, "state\t%s\n", dstate(d->state));
2752         p = seprint(p, e, "type\t%s", type[d->type]);
2753         if(d->type == Sata)
2754                 p = seprint(p, e, " sig %.8ux", getsig(d));
2755         p = seprint(p, e, "\n");
2756         if(d->state == Dready){
2757                 p = seprint(p, e, "model\t%s\n", d->model);
2758                 p = seprint(p, e, "serial\t%s\n", d->serial);
2759                 p = seprint(p, e, "firm\t%s\n", d->firmware);
2760                 p = seprint(p, e, "wwn\t%llux\n", d->wwn);
2761                 p = msrctlsata(d, p, e);
2762         }
2763         p = rctldebug(p, e, c, d);
2764         p = seprint(p, e, "geometry %llud %lud\n", d->sectors, u->secsize);
2765         return p - op;
2766 }
2767
2768 static void
2769 forcestate(Drive *d, char *state)
2770 {
2771         int i;
2772
2773         for(i = 1; i < nelem(diskstates); i++)
2774                 if(strcmp(state, diskstates[i]) == 0)
2775                         break;
2776         if(i == nelem(diskstates))
2777                 error(Ebadctl);
2778         ilock(d);
2779         d->state = 1 << i - 1;
2780         statechange(d);
2781         iunlock(d);
2782 }
2783
2784 static int
2785 mswctl(SDunit *u, Cmdbuf *cmd)
2786 {
2787         char **f;
2788         Ctlr *c;
2789         Drive *d;
2790
2791         c = u->dev->ctlr;
2792         d = c->drive + u->subno;
2793         f = cmd->f;
2794         if(strcmp(f[0], "state") == 0)
2795                 forcestate(d, f[1]? f[1]: "null");
2796         else
2797                 cmderror(cmd, Ebadctl);
2798         return 0;
2799 }
2800
2801 static int
2802 mswtopctl(SDev*, Cmdbuf *cmd)
2803 {
2804         char **f;
2805         int *v;
2806
2807         f = cmd->f;
2808         v = 0;
2809         if(strcmp(f[0], "debug") == 0)
2810                 v = &debug;
2811         else if(strcmp(f[0], "idprint") == 0)
2812                 v = &idebug;
2813         else if(strcmp(f[0], "aprint") == 0)
2814                 v = &adebug;
2815         else
2816                 cmderror(cmd, Ebadctl);
2817         if(cmd->nf == 1)
2818                 *v ^= 1;
2819         else if(cmd->nf == 2)
2820                 *v = strcmp(f[1], "on") == 0;
2821         else
2822                 cmderror(cmd, Ebadarg);
2823         return 0;
2824 }
2825
2826 SDifc sdodinifc = {
2827         "odin",
2828         mspnp,
2829         nil,
2830         msenable,
2831         msdisable,
2832         msverify,
2833         msonline,
2834         msrio,
2835         msrctl,
2836         mswctl,
2837         scsibio,
2838         nil,            /* probe */
2839         nil,            /* clear */
2840         nil,
2841         mswtopctl,
2842         msataio,
2843 };