]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libfis/fis.c
git/branch: revert optimization fully
[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) == 0){
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                         /*
292                          * not acceptable for comreset to
293                          * wipe out device configuration.
294                          * reject drive.
295                         i = gbit16(id + 78) & gbit16(id + 79);
296                         if((i & 1<<6) == 0)
297                                 return -1;
298                          */
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, pa;
311
312         if(f->sig>>16 == 0xeb14)
313                 return 0;
314         f->lsectsz = 512;
315         f->physshift = 0;
316         f->physalign = 0;
317         i = gbit16(id + 106);
318         if(i >> 14 != 1)
319                 return f->lsectsz;
320         if((i & (1<<12)) && (sw = gbit32(id + 117)) >= 256)
321                 f->lsectsz = sw * 2;
322         if(i & 1<<13){
323                 f->physshift = i & 7;
324                 if((pa = gbit16(id + 209)) & 0x4000)
325                         f->physalign = pa & 0x3fff;
326         }
327         return f->lsectsz;
328 }
329
330 uvlong
331 idwwn(Sfis*, ushort *id)
332 {
333         uvlong u;
334
335         u = 0;
336         if(id[108]>>12 == 5){
337                 u |= (uvlong)gbit16(id + 108) << 48;
338                 u |= (uvlong)gbit16(id + 109) << 32;
339                 u |= gbit16(id + 110) << 16;
340                 u |= gbit16(id + 111) << 0;
341         }
342         return u;
343 }
344
345 void
346 idmove(char *p, ushort *u, int n)
347 {
348         int i;
349         char *op, *e, *s;
350
351         op = p;
352         s = (char*)u;
353         for(i = 0; i < n; i += 2){
354                 *p++ = s[i + 1];
355                 *p++ = s[i + 0];
356         }
357         *p = 0;
358         while(p > op && *--p == ' ')
359                 *p = 0;
360         e = p;
361         p = op;
362         while(*p == ' ')
363                 p++;
364         memmove(op, p, n - (e - p));
365 }
366
367 char*
368 pflag(char *s, char *e, Sfis *f)
369 {
370         ushort i, u;
371
372         u = f->feat;
373         for(i = 0; i < Dnflag; i++)
374                 if(u & (1 << i))
375                         s = seprint(s, e, "%s ", flagname[i]);
376         return seprint(s, e, "\n");
377 }
378
379 int
380 atapirwfis(Sfis *f, uchar *c, uchar *cdb, int cdblen, int ndata)
381 {
382         int fill, len;
383
384         fill = f->feat&Datapi16? 16: 12;
385         if((len = cdblen) > fill)
386                 len = fill;
387         memmove(c + 0x40, cdb, len);
388         memset(c + 0x40 + len, 0, fill - len);
389
390         c[Ftype] = H2dev;
391         c[Fflags] = Fiscmd;
392         c[Fcmd] = Ataobs;
393         if(ndata != 0)
394                 c[Ffeat] = 1;   /* dma */
395         else
396                 c[Ffeat] = 0;   /* features (exp); */
397         c[Flba0] = 0;   
398         c[Flba8] = ndata;
399         c[Flba16] = ndata >> 8;
400         c[Fdev] = Ataobs;
401         memset(c + 8, 0, Fissize - 8);
402         return P28|Ppkt;
403 }
404
405 int
406 rwfis(Sfis *f, uchar *c, int rw, int nsect, uvlong lba)
407 {
408         uchar acmd, llba, udma;
409         static uchar tab[2][2][2] = { 0x20, 0x24, 0x30, 0x34, 0xc8, 0x25, 0xca, 0x35, };
410         static uchar ptab[2][2][2] = {
411                 Pin|Ppio|P28,   Pin|Ppio|P48,
412                 Pout|Ppio|P28,  Pout|Ppio|P48,
413                 Pin|Pdma|P28,   Pin|Pdma|P48,
414                 Pout|Pdma|P28,  Pout|Pdma|P48,
415         };
416
417         udma = f->udma != 0xff;
418         llba = (f->feat & Dllba) != 0;
419         acmd = tab[udma][rw][llba];
420
421         c[Ftype] = 0x27;
422         c[Fflags] = 0x80;
423         c[Fcmd] = acmd;
424         c[Ffeat] = 0;
425
426         c[Flba0] = lba;
427         c[Flba8] = lba >> 8;
428         c[Flba16] = lba >> 16;
429         c[Fdev] = Ataobs | Atalba;
430         if(llba == 0)
431                 c[Fdev] |= (lba>>24) & 0xf;
432
433         c[Flba24] = lba >> 24;
434         c[Flba32] = lba >> 32;
435         c[Flba40] = lba >> 40;
436         c[Ffeat8] = 0;
437
438         c[Fsc] = nsect;
439         c[Fsc8] = nsect >> 8;
440         c[Ficc] = 0;
441         c[Fcontrol] = 0;
442
443         memset(c + 16, 0, Fissize - 16);
444         return ptab[udma][rw][llba];
445 }
446
447 uvlong
448 fisrw(Sfis *, uchar *c, int *n)
449 {
450         uvlong lba;
451
452         lba = c[Flba0];
453         lba |= c[Flba8] << 8;
454         lba |= c[Flba16] << 16;
455         lba |= c[Flba24] << 24;
456         lba |= (uvlong)(c[Flba32] | c[Flba40]<<8) << 32;
457
458         *n = c[Fsc];
459         *n |= c[Fsc8] << 8;
460
461         return lba;
462 }
463
464 void
465 sigtofis(Sfis *f, uchar *c)
466 {
467         uint u;
468
469         u = f->sig;
470         memset(c, 0, Fissize);
471         c[Ftype] = 0x34;
472         c[Fflags] = 0x00;
473         c[Fcmd] = 0x50;
474         c[Ffeat] = 0x01;
475         c[Flba0] = u >> 8;
476         c[Flba8] = u >> 16;
477         c[Flba16] = u >> 24;
478         c[Fdev] = Ataobs;
479         c[Fsc] = u;
480 }
481
482 uint
483 fistosig(uchar *u)
484 {
485         return u[Fsc] | u[Flba0]<<8 | u[Flba8]<<16 | u[Flba16]<<24;
486 }
487
488
489 /* sas smp */
490 void
491 smpskelframe(Cfis *f, uchar *c, int m)
492 {
493         memset(c, 0, Fissize);
494         c[Ftype] = 0x40;
495         c[Fflags] = m;
496         if(f->phyid)
497                 c[Flba32] = f->phyid;
498 }
499
500 uint
501 sashash(uvlong u)
502 {
503         uint poly, msb, l, r;
504         uvlong m;
505
506         r = 0;
507         poly = 0x01db2777;
508         msb = 0x01000000;
509         for(m = 1ull<<63; m > 0; m >>= 1){
510                 l = 0;
511                 if(m & u)
512                         l = msb;
513                 r <<= 1;
514                 r ^= l;
515                 if(r & msb)
516                         r ^= poly;
517         }
518         return r & 0xffffff;
519 }
520
521 uchar*
522 sasbhash(uchar *t, uchar *s)
523 {
524         uint poly, msb, l, r, i, j;
525
526         r = 0;
527         poly = 0x01db2777;
528         msb = 0x01000000;
529         for(i = 0; i < 8; i++)
530                 for(j = 0x80; j != 0; j >>= 1){
531                         l = 0;
532                         if(s[i] & j)
533                                 l = msb;
534                         r <<= 1;
535                         r ^= l;
536                         if(r & msb)
537                                 r ^= poly;
538                 }
539         t[0] = r>>16;
540         t[1] = r>>8;
541         t[2] = r;
542         return t;
543 }