]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libfis/fis.c
merge
[plan9front.git] / sys / src / libfis / fis.c
1 /*
2  * sata fises and sas frames
3  * copyright © 2009-2010 erik quanstrom
4  */
5 #include <u.h>
6 #include <libc.h>
7 #include <fis.h>
8
9 static char *flagname[9] = {
10         "lba",
11         "llba",
12         "smart",
13         "power",
14         "nop",
15         "atapi",
16         "atapi16",
17         "ata8",
18         "sct",
19 };
20
21 /*
22  * ata8 standard (llba) cmd layout
23  *
24  * feature      16 bits
25  * count                16 bits
26  * lba          48 bits
27  * device               8 bits
28  * command      8 bits
29  *
30  * response:
31  *
32  * status               8 bits
33  * error                8 bits
34  * reason               8 bits
35  * count                8 bits
36  * sstatus              8 bits
37  * sactive              8 bits
38 */
39
40 /*
41  * sata fis layout for fistype 0x27: host-to-device:
42  *
43  * 0    fistype
44  * 1    fis flags
45  * 2    ata command
46  * 3    features
47  * 4    sector  lba low 7:0
48  * 5    cyl low lba mid 15:8
49  * 6    cyl hi  lba hi  23:16
50  * 7    device / head
51  * 8    sec exp lba     31:24
52  * 9    cy low e        lba     39:32
53  * 10   cy hi e lba     48:40
54  * 11   features (exp)
55  * 12   sector count
56  * 13   sector count (exp)
57  * 14   r
58  * 15   control
59  */
60
61 void
62 setfissig(Sfis *x, uint sig)
63 {
64         x->sig = sig;
65 }
66
67 void
68 skelfis(uchar *c)
69 {
70         memset(c, 0, Fissize);
71         c[Ftype] = H2dev;
72         c[Fflags] = Fiscmd;
73         c[Fdev] = Ataobs;
74 }
75
76 int
77 nopfis(Sfis*, uchar *c, int srst)
78 {
79         skelfis(c);
80         if(srst){
81                 c[Fflags] &= ~Fiscmd;
82                 c[Fcontrol] = 1<<2;
83                 return Preset|P28;
84         }
85         return Pnd|P28;
86 }
87
88 int
89 txmodefis(Sfis *f, uchar *c, uchar d)
90 {
91         int m;
92
93         /* hack */
94         if((f->sig >> 16) == 0xeb14)
95                 return -1;
96         m = 0x40;
97         if(d == 0xff){
98                 d = 0;
99                 m = 0;
100         }
101         skelfis(c);
102         c[Fcmd] = 0xef;
103         c[Ffeat] = 3;                   /* set transfer mode */
104         c[Fsc] = m | d;                 /* sector count */
105         return Pnd|P28;
106 }
107
108 int
109 featfis(Sfis*, uchar *c, uchar f)
110 {
111         skelfis(c);
112         c[Fcmd] = 0xef;
113         c[Ffeat] = f;
114         return Pnd|P28;
115 }
116
117 int
118 identifyfis(Sfis *f, uchar *c)
119 {
120         static uchar tab[] = { 0xec, 0xa1, };
121
122         skelfis(c);
123         c[Fcmd] = tab[f->sig>>16 == 0xeb14];
124         return Pin|Ppio|P28|P512;
125 }
126
127 int
128 flushcachefis(Sfis *f, uchar *c)
129 {
130         static uchar tab[2] = {0xe7, 0xea};
131         static uchar ptab[2] = {Pnd|P28, Pnd|P48};
132         int llba;
133
134         llba = (f->feat & Dllba) != 0;
135         skelfis(c);
136         c[Fcmd] = tab[llba];
137         return ptab[llba];
138 }
139
140 static ushort
141 gbit16(void *a)
142 {
143         ushort j;
144         uchar *i;
145
146         i = a;
147         j  = i[1] << 8;
148         j |= i[0];
149         return j;
150 }
151
152 static uint
153 gbit32(void *a)
154 {
155         uint j;
156         uchar *i;
157
158         i = a;
159         j  = i[3] << 24;
160         j |= i[2] << 16;
161         j |= i[1] << 8;
162         j |= i[0];
163         return j;
164 }
165
166 static uvlong
167 gbit64(void *a)
168 {
169         uchar *i;
170
171         i = a;
172         return (uvlong)gbit32(i+4) << 32 | gbit32(a);
173 }
174
175 ushort
176 id16(ushort *id, int i)
177 {
178         return gbit16(id+i);
179 }
180
181 uint
182 id32(ushort *id, int i)
183 {
184         return gbit32(id+i);
185 }
186
187 uvlong
188 id64(ushort *id, int i)
189 {
190         return gbit64(id+i);
191 }
192
193 /* acs-2 §7.18.7.4 */
194 static ushort puistab[] = {
195         0x37c8, Pspinup,
196         0x738c, Pspinup | Pidready,
197         0x8c73, 0,
198         0xc837, Pidready,
199 };
200
201 int
202 idpuis(ushort *id)
203 {
204         ushort u, i;
205
206         u = gbit16(id + 2);
207         for(i = 0; i < nelem(puistab); i += 2)
208                 if(u == puistab[i])
209                         return puistab[i + 1];
210         return Pidready;        /* annoying cdroms */
211 }
212
213 static ushort
214 onesc(ushort *id)
215 {
216         ushort u;
217
218         u = gbit16(id);
219         if(u == 0xffff)
220                 u = 0;
221         return u;
222 }
223
224 enum{
225         Idmasp  = 1<<8,
226         Ilbasp  = 1<<9,
227         Illba   = 1<<10,
228 };
229
230 vlong
231 idfeat(Sfis *f, ushort *id)
232 {
233         int i, j;
234         vlong s;
235
236         f->feat = 0;
237         if(f->sig>>16 == 0xeb14)
238                 f->feat |= Datapi;
239         i = gbit16(id + 49);
240         if((i & Ilbasp) == 0){
241                 if(gbit16(id + 53) & 1){
242                         f->c = gbit16(id + 1);
243                         f->h = gbit16(id + 3);
244                         f->s = gbit16(id + 6);
245                 }else{
246                         f->c = gbit16(id + 54);
247                         f->h = gbit16(id + 55);
248                         f->s = gbit16(id + 56);
249                 }
250                 s = f->c*f->h*f->s;
251         }else{
252                 f->c = f->h = f->s = 0;
253                 f->feat |= Dlba;
254                 j = gbit16(id + 83) | gbit16(id + 86);
255                 if(j & Illba){
256                         f->feat |= Dllba;
257                         s = gbit64(id + 100);
258                 }else
259                         s = gbit32(id + 60);
260         }
261         f->udma = 0xff;
262         if(i & Idmasp)
263         if(gbit16(id + 53) & 4)
264                 for(i = gbit16(id + 88) & 0x7f; i; i >>= 1)
265                         f->udma++;
266
267         if(f->feat & Datapi){
268                 i = gbit16(id + 0);
269                 if(i & 1)
270                         f->feat |= Datapi16;
271         }
272
273         i = gbit16(id+83);
274         if((i>>14) == 1){
275                 if(i & (1<<3))
276                         f->feat |= Dpower;
277                 i = gbit16(id + 82);
278                 if(i & 1)
279                         f->feat |= Dsmart;
280                 if(i & (1<<14))
281                         f->feat |= Dnop;
282         }
283         i = onesc(id + 80);
284         if(i & 1<<8){
285                 f->feat |= Data8;
286                 i = onesc(id + 222);                    /* sata? */
287                 j = onesc(id + 76);
288                 if(i != 0 && i >> 12 == 1 && j != 0){
289                         j >>= 1;
290                         f->speeds = j & 7;
291                         i = gbit16(id + 78) & gbit16(id + 79);
292                         /*
293                          * not acceptable for comreset to
294                          * wipe out device configuration.
295                          * reject drive.
296                          */
297                         if((i & 1<<6) == 0)
298                                 return -1;
299                 }
300         }
301         if(gbit16(id + 206) & 1)
302                 f->feat |= Dsct;
303         idss(f, id);
304         return s;
305 }
306
307 int
308 idss(Sfis *f, ushort *id)
309 {
310         uint sw, i;
311
312         if(f->sig>>16 == 0xeb14)
313                 return 0;
314         f->lsectsz = 512;
315         f->physshift = 0;
316         i = gbit16(id + 106);
317         if(i >> 14 != 1)
318                 return f->lsectsz;
319         if((sw = gbit32(id + 117)) >= 256)
320                 f->lsectsz = sw * 2;
321         if(i & 1<<13)
322                 f->physshift = i & 7;
323         return f->lsectsz * (1<<f->physshift);
324 }
325
326 uvlong
327 idwwn(Sfis*, ushort *id)
328 {
329         uvlong u;
330
331         u = 0;
332         if(id[108]>>12 == 5){
333                 u |= (uvlong)gbit16(id + 108) << 48;
334                 u |= (uvlong)gbit16(id + 109) << 32;
335                 u |= gbit16(id + 110) << 16;
336                 u |= gbit16(id + 111) << 0;
337         }
338         return u;
339 }
340
341 void
342 idmove(char *p, ushort *u, int n)
343 {
344         int i;
345         char *op, *e, *s;
346
347         op = p;
348         s = (char*)u;
349         for(i = 0; i < n; i += 2){
350                 *p++ = s[i + 1];
351                 *p++ = s[i + 0];
352         }
353         *p = 0;
354         while(p > op && *--p == ' ')
355                 *p = 0;
356         e = p;
357         p = op;
358         while(*p == ' ')
359                 p++;
360         memmove(op, p, n - (e - p));
361 }
362
363 char*
364 pflag(char *s, char *e, Sfis *f)
365 {
366         ushort i, u;
367
368         u = f->feat;
369         for(i = 0; i < Dnflag; i++)
370                 if(u & (1 << i))
371                         s = seprint(s, e, "%s ", flagname[i]);
372         return seprint(s, e, "\n");
373 }
374
375 int
376 atapirwfis(Sfis *f, uchar *c, uchar *cdb, int cdblen, int ndata)
377 {
378         int fill, len;
379
380         fill = f->feat&Datapi16? 16: 12;
381         if((len = cdblen) > fill)
382                 len = fill;
383         memmove(c + 0x40, cdb, len);
384         memset(c + 0x40 + len, 0, fill - len);
385
386         c[Ftype] = H2dev;
387         c[Fflags] = Fiscmd;
388         c[Fcmd] = Ataobs;
389         if(ndata != 0)
390                 c[Ffeat] = 1;   /* dma */
391         else
392                 c[Ffeat] = 0;   /* features (exp); */
393         c[Flba0] = 0;   
394         c[Flba8] = ndata;
395         c[Flba16] = ndata >> 8;
396         c[Fdev] = Ataobs;
397         memset(c + 8, 0, Fissize - 8);
398         return P28|Ppkt;
399 }
400
401 int
402 rwfis(Sfis *f, uchar *c, int rw, int nsect, uvlong lba)
403 {
404         uchar acmd, llba, udma;
405         static uchar tab[2][2][2] = { 0x20, 0x24, 0x30, 0x34, 0xc8, 0x25, 0xca, 0x35, };
406         static uchar ptab[2][2][2] = {
407                 Pin|Ppio|P28,   Pin|Ppio|P48,
408                 Pout|Ppio|P28,  Pout|Ppio|P48,
409                 Pin|Pdma|P28,   Pin|Pdma|P48,
410                 Pout|Pdma|P28,  Pout|Pdma|P48,
411         };
412
413         nsect >>= f->physshift;
414         lba >>= f->physshift;
415
416         udma = f->udma != 0xff;
417         llba = (f->feat & Dllba) != 0;
418         acmd = tab[udma][rw][llba];
419
420         c[Ftype] = 0x27;
421         c[Fflags] = 0x80;
422         c[Fcmd] = acmd;
423         c[Ffeat] = 0;
424
425         c[Flba0] = lba;
426         c[Flba8] = lba >> 8;
427         c[Flba16] = lba >> 16;
428         c[Fdev] = Ataobs | Atalba;
429         if(llba == 0)
430                 c[Fdev] |= (lba>>24) & 0xf;
431
432         c[Flba24] = lba >> 24;
433         c[Flba32] = lba >> 32;
434         c[Flba40] = lba >> 48;
435         c[Ffeat8] = 0;
436
437         c[Fsc] = nsect;
438         c[Fsc8] = nsect >> 8;
439         c[Ficc] = 0;
440         c[Fcontrol] = 0;
441
442         memset(c + 16, 0, Fissize - 16);
443         return ptab[udma][rw][llba];
444 }
445
446 uvlong
447 fisrw(Sfis *f, uchar *c, int *n)
448 {
449         uvlong lba;
450
451         lba = c[Flba0];
452         lba |= c[Flba8] << 8;
453         lba |= c[Flba16] << 16;
454         lba |= c[Flba24] << 24;
455         lba |= (uvlong)(c[Flba32] | c[Flba40]<<8) << 32;
456
457         *n = c[Fsc];
458         *n |= c[Fsc8] << 8;
459
460         *n >>= f->physshift;
461         lba >>= f->physshift;
462
463         return lba;
464 }
465
466 void
467 sigtofis(Sfis *f, uchar *c)
468 {
469         uint u;
470
471         u = f->sig;
472         memset(c, 0, Fissize);
473         c[Ftype] = 0x34;
474         c[Fflags] = 0x00;
475         c[Fcmd] = 0x50;
476         c[Ffeat] = 0x01;
477         c[Flba0] = u >> 8;
478         c[Flba8] = u >> 16;
479         c[Flba16] = u >> 24;
480         c[Fdev] = Ataobs;
481         c[Fsc] = u;
482 }
483
484 uint
485 fistosig(uchar *u)
486 {
487         return u[Fsc] | u[Flba0]<<8 | u[Flba8]<<16 | u[Flba16]<<24;
488 }
489
490
491 /* sas smp */
492 void
493 smpskelframe(Cfis *f, uchar *c, int m)
494 {
495         memset(c, 0, Fissize);
496         c[Ftype] = 0x40;
497         c[Fflags] = m;
498         if(f->phyid)
499                 c[Flba32] = f->phyid;
500 }
501
502 uint
503 sashash(uvlong u)
504 {
505         uint poly, msb, l, r;
506         uvlong m;
507
508         r = 0;
509         poly = 0x01db2777;
510         msb = 0x01000000;
511         for(m = 1ull<<63; m > 0; m >>= 1){
512                 l = 0;
513                 if(m & u)
514                         l = msb;
515                 r <<= 1;
516                 r ^= l;
517                 if(r & msb)
518                         r ^= poly;
519         }
520         return r & 0xffffff;
521 }
522
523 uchar*
524 sasbhash(uchar *t, uchar *s)
525 {
526         uint poly, msb, l, r, i, j;
527
528         r = 0;
529         poly = 0x01db2777;
530         msb = 0x01000000;
531         for(i = 0; i < 8; i++)
532                 for(j = 0x80; j != 0; j >>= 1){
533                         l = 0;
534                         if(s[i] & j)
535                                 l = msb;
536                         r <<= 1;
537                         r ^= l;
538                         if(r & msb)
539                                 r ^= poly;
540                 }
541         t[0] = r>>16;
542         t[1] = r>>8;
543         t[2] = r;
544         return t;
545 }