]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/atazz/main.c
pc, pc64: disable all pci devices for /dev/reboot
[plan9front.git] / sys / src / cmd / atazz / main.c
1 #include <u.h>
2 #include <libc.h>
3 #include <fis.h>
4 #include "atazz.h"
5 #include "tabs.h"
6
7 #pragma varargck        argpos  eprint  1
8 #pragma varargck        type    "π"    char**
9
10 enum {
11         Dontread        = -2,
12 };
13
14 int     interrupted;
15 int     rflag;
16 int     squelch;
17 int     scttrace;
18 uchar   issuetr[0x100];
19
20 Atatab  *idcmd;
21 Atatab  *idpktcmd;
22 Atatab  *sigcmd;
23 Atatab  *sctread;
24 Atatab  *sctissue;
25
26 int
27 πfmt(Fmt *f)
28 {
29         char **p;
30
31         p = va_arg(f->args, char**);
32         if(p == nil)
33                 return fmtstrcpy(f, "<nil**>");
34         for(; *p; p++){
35                 fmtstrcpy(f, *p);
36                 if(p[1] != nil)
37                         fmtstrcpy(f, " ");
38         }
39         return 0;
40 }
41
42 int
43 eprint(char *fmt, ...)
44 {
45         int n;
46         va_list args;
47
48         if(squelch)
49                 return 0;
50 //      Bflush(&out);
51
52         va_start(args, fmt);
53         n = vfprint(2, fmt, args);
54         va_end(args);
55         return n;
56 }
57
58 void
59 fisset(Req *r, uint i, uint v)
60 {
61         if(r->fisbits & 1<<i)
62                 return;
63         r->fisbits |= 1<<i;
64         r->cmd.fis[i] = v;
65 }
66
67 void
68 prreq(Req *r)
69 {
70         uchar *u;
71
72         print("%.2ux %.2ux\n", r->cmd.sdcmd, r->cmd.ataproto);
73         u = r->cmd.fis;
74         print("%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux ",
75                 u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7]);
76         u += 8;
77         print("%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux\n",
78                 u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7]);
79 }
80
81 char*
82 protostr(char *p, char *e, int pr)
83 {
84         char *s;
85
86         *p = 0;
87         if(pr & P28)
88                 p = seprint(p, e, "28:");
89         else
90                 p = seprint(p, e, "28:");
91         switch(pr & Pprotom){
92         default:
93                 s = "unk";
94                 break;
95         case Ppkt:
96                 s = "pkt";
97                 break;
98         case Pdiag:
99                 s = "dig";
100                 break;
101         case Preset:
102                 s = "rst";
103                 break;
104         case Pdmq:
105                 s = "dmq";
106                 break;
107         case Pdma:
108                 s = "dma";
109                 break;
110         case Ppio:
111                 s = "pio";
112                 break;
113         }
114         p = seprint(p, e, "%s:", s);
115         switch(pr & Pdatam){
116         default:
117                 s = "nd";
118                 break;
119         case Pin:
120                 s = "in";
121                 break;
122         case Pout:
123                 s = "out";
124                 break;
125         }
126         p = seprint(p, e, "%s", s);
127         return p;
128 }
129
130 void
131 displaycmd(Req *r, Atatab *a)
132 {
133         char buf[32];
134         int i;
135
136         if(a->cc > nelem(issuetr) || !issuetr[a->cc])
137                 return;
138         protostr(buf, buf + sizeof buf, a->protocol);
139         fprint(2, "cmd %s:%2ux ", buf, a->cc);
140         for(i = 0; i < 16; i++)
141                 fprint(2, "%.2ux", r->cmd.fis[i]);
142         fprint(2, "\n");
143 }
144
145 int
146 issueata(Req *r, Atatab *a, Dev *d)
147 {
148         uchar u;
149         int n, ok, pr, rv;
150
151         r->haverfis = 0;
152         pr = a->protocol & Pdatam;
153         r->data = realloc(r->data, r->count);
154         if(r->data == nil && r->count > 0)
155                 sysfatal("realloc: %r");
156         if(r->data == nil && pr != Pnd)
157                 sysfatal("no data for cmd %.2ux", a->cc);
158         if(0 && r->fisbits)
159                 print("fisbits %.16b\n", r->fisbits);
160         r->cmd.sdcmd = 0xff;
161         r->cmd.ataproto = a->protocol;
162         if(a->cc & 0xff00)
163                 fisset(r, 0, a->cc >> 8);
164         else
165                 fisset(r, 0, H2dev);
166         fisset(r, 1, Fiscmd);
167         fisset(r, 2, a->cc);
168         switch(pr){
169         case Pout:
170                 if(r->rfd != Dontread){
171                         n = readn(r->rfd, r->data, r->count);
172                         if(n != r->count){
173                                 if(n == -1)
174                                         eprint("!short src read %r\n");
175                                 else
176                                         eprint("!short src read %d wanted %lld\n", n, r->count);
177                                 return -1;
178                         }
179                 }
180         case Pnd:
181         case Pin:
182                 if(0 && (d->feat & Dlba) == 0 && (d->c | d->h | d->s)){
183                         int c, h, s;
184                         c = r->lba / (d->s * d->h);
185                         h = (r->lba / d->s) % d->h;
186                         s = (r->lba % d->s) + 1;
187 print("%d %d %d\n", c, h, s);
188                         fisset(r, 4, s);
189                         fisset(r, 5, c);
190                         fisset(r, 6, c >> 8);
191                         fisset(r, 7, Ataobs | h);
192                 }else{
193                         fisset(r, 4, r->lba);
194                         fisset(r, 5, r->lba >> 8);
195                         fisset(r, 6, r->lba >> 16);
196                         u = Ataobs;
197                         if(pr == Pin || pr == Pout)
198                                 u |= Atalba;
199                         if((d->feat & Dllba) == 0)
200                                 u |= (r->lba >> 24) & 7;
201                         fisset(r, 7, u);
202                         fisset(r, 8, r->lba >> 24);
203                         fisset(r, 9, r->lba >> 32);
204                         fisset(r, 10, r->lba >> 48);
205                 }
206                 fisset(r, 12, r->nsect);
207                 fisset(r, 13, r->nsect >> 8);
208                 break;
209         }
210         fisset(r, 7, Ataobs);
211         displaycmd(r, a);
212         if(write(d->fd, &r->cmd, Cmdsz) != Cmdsz){
213                 eprint("fis write error: %r\n");
214                 return -1;
215         }
216
217         werrstr("");
218         switch(pr){
219         default:
220                 ok = read(d->fd, "", 0) == 0;
221                 break;
222         case Pin:
223                 ok = read(d->fd, r->data, r->count) == r->count;
224                 r->lba += r->nsect;
225                 break;
226         case Pout:
227                 ok = write(d->fd, r->data, r->count) == r->count;
228                 r->lba += r->nsect;
229                 break;
230         }
231         rv = 0;
232         if(ok == 0){
233                 eprint("xfer error: %.2ux %r\n", a->cc);
234                 rv = -1;
235         }
236         switch(n = read(d->fd, &r->reply, Replysz)){
237         case Replysz:
238                 r->haverfis = 1;
239                 return rv;
240         case -1:
241                 eprint("status fis read error: %r\n");
242                 return -1;
243         default:
244                 eprint("status fis read error: short read: %d of %d\n", n, Replysz);
245                 return -1;
246         }
247 }
248
249 /*
250  * cheezy code; just issue a inquiry.  use scuzz
251  * for real work with atapi devices
252  */
253 int
254 issuepkt(Req *r, Atatab *a, Dev *d)
255 {
256         char *p;
257         uchar *u;
258         int n, rv;
259
260         r->haverfis = 0;
261         r->count = 128;
262         r->data = realloc(r->data, r->count);
263         if(r->data == nil && r->count > 0)
264                 sysfatal("realloc: %r");
265         r->cmd.sdcmd = 0xff;
266         r->cmd.ataproto = a->protocol;
267         memset(r->cmd.fis, 0, Fissize);
268
269         u = r->cmd.fis;
270         u[0] = 0x12;
271         u[4] = 128-1;
272         displaycmd(r, a);
273
274         if(write(d->fd, &r->cmd, 6 + 2) != 6 + 2){
275                 eprint("fis write error: %r\n");
276                 return -1;
277         }
278         n = read(d->fd, r->data, r->count);
279         rv = 0;
280         if(n == -1){
281                 eprint("xfer error: %.2ux %r\n", a->cc);
282                 rv = -1;
283         }
284
285         print("n is %d (%lld)\n", n, r->count);
286         if(n > 32){
287                 p = (char*)r->data;
288                 print("%.8s %.16s\n", p + 8, p + 16);
289         }
290
291         u = (uchar*)&r->reply;
292         n = read(d->fd, u, Replysz);
293         if(n < 0){
294                 eprint("status fis read error (%d): %r\n", n);
295                 return -1;
296         }
297         
298         if(n < Replysz)
299                 memset(u + n, 0, Replysz - n);
300         r->haverfis = 1;
301         return rv;
302 }
303
304 /*
305  * silly protocol:
306  * 1.  use write log ext 0xe0 to fill out the command
307  * 2.  use write log ext 0xe1 to write or data (if any)
308  * 3.  use read log ext 0xe0 to nab status.  polled
309  */
310 void
311 sctreq(Req *r)
312 {
313         memset(r, 0, sizeof *r);
314         r->rfd = Dontread;
315 }
316
317 char*
318 sctrsp(Req *r)
319 {
320         uint i;
321         static char buf[32];
322
323         if(!r->haverfis)
324                 return "no rfis";
325         if((r->reply.fis[Frerror] & (Eidnf | Eabrt)) == 0)
326                 return nil;
327         i = r->reply.fis[Fsc] | r->reply.fis[Flba0]<<8;
328         if(i == 0xffff)
329                 return "in progress";
330         else if(i == 0){
331                 snprint(buf, sizeof buf, "unknown %.2ux", r->reply.fis[Frerror]);
332                 return buf;
333         }else if(i < nelem(sctetab))
334                 return sctetab[i];
335         else
336                 return "<bad>";
337 }
338
339 char*
340 sctready(Dev *d, int sec)
341 {
342         char *s;
343         int i;
344         Req r;
345         static char e[ERRMAX];
346
347         for(;;){
348                 if(interrupted){
349                         s = "interrupted";
350                         break;
351                 }
352                 sctreq(&r);
353                 fisset(&r, Fsc, 1);
354                 fisset(&r, Flba0, 0xe0);
355                 r.count = 512;
356                 i = issueata(&r, sctread, d);
357                 free(r.data);
358                 if(i == -1){
359                         rerrstr(e, ERRMAX);
360                         s = e;
361                         break;
362                 }
363                 if((r.cmd.fis[Fsc] | r.cmd.fis[Fsc8]<<8) != 0xffff){
364                         s = sctrsp(&r);
365                         break;
366                 }
367                 if(sec == 0){
368                         s = "timeout";
369                         break;
370                 }
371                 sleep(1000);
372                 sec--;
373         }
374         return s;
375 }
376
377 typedef struct Sttab Sttab;
378 struct Sttab {
379         int     o;
380         int     sz;
381         char    *name;
382 };
383
384 Sttab sctt[] = {
385         0,      2,      "version",
386         2,      2,      "period",
387         4,      2,      "intval",
388         6,      1,      "max op",
389         7,      1,      "max",
390         8,      1,      "min op",
391         9,      1,      "min",
392 };
393
394 void
395 sctttab(Req *r)
396 {
397         char c, buf[10];
398         int i, n, l, d;
399         uchar *u;
400
401         u = r->data;
402         for(i = 0; i < nelem(sctt); i++){
403                 switch(sctt[i].sz){
404                 case 1:
405                         c = u[sctt[i].o];
406                         print("%s\t%d\n", sctt[i].name, c);
407                         break;
408                 case 2:
409                         d = w(u + sctt[i].o);
410                         print("%s\t%ud\n", sctt[i].name, d);
411                         break;
412                 }
413         }
414         n = w(u + 30);
415         l = w(u + 32);
416         for(i = 0; i < n; i++){
417                 c = u[34 + (l + i) % n];
418                 if((uchar)c == 0x80)
419                         snprint(buf, sizeof buf, "xx");
420                 else
421                         snprint(buf, sizeof buf, "%d", c);
422                 d = i%10;
423                 if(d == 0)
424                         print("\nt%d\t%d", i, c);
425                 else
426                         print("% .2d", c);
427         }
428         if(i%10)
429                 print("\n");
430 }
431
432 static struct {
433         uint    code;
434         char    *s;
435         char    *ms;
436 } fxtab[] = {
437         0x00010001,     "set features", 0,
438         0x00010002,     "enabled",      0,
439         0x00010003,     "disabled",     0,
440
441         0x00020001,     "enabled",      0,
442         0x00020002,     "disabled",     0,
443
444         0x0003ffff,     "minute",       "minutes",
445 };
446
447 void
448 sctfcout(ushort *u, Req *r)
449 {
450         uchar *f;
451         ushort v;
452         uint c, m, i;
453
454         f = r->reply.fis;
455         switch(u[1]){
456         case 1:
457         case 2:
458                 v = f[Fsc] | f[Flba0]<<8;
459                 c = u[2]<<16 | v;
460                 m = u[2]<<16 | 0xffff;
461                 for(i = 0; i < nelem(fxtab); i++)
462                         if(fxtab[i].code == c)
463                                 print("%s\n", fxtab[i].s);
464                         else if(fxtab[i].code == m)
465                                 print("%d %s\n", v, v>1? fxtab[i].ms: fxtab[i].s);
466                 break;
467         case 3:
468                 v = f[Fsc] | f[Flba0]<<8;
469                 if(v & 1)
470                         print("preserve\n");
471                 else
472                         print("volatile\n");
473                 break;
474         }
475 }
476
477 void
478 scterout(ushort *u, Req *r)
479 {
480         uchar *f;
481         uint v;
482
483         f = r->reply.fis;
484         switch(u[1]){
485         case 2:
486                 v = f[Fsc] | f[Flba0]<<8;
487                 v *= 100;
488                 print("%dms\n", v);
489         }
490 }
491
492 void
493 sctout(ushort *u, Req *r)
494 {
495         switch(u[0]){
496         case 5:
497                 sctttab(r);
498                 break;
499         case 4:
500                 sctfcout(u, r);
501                 break;
502         case 3:
503                 scterout(u, r);
504                 break;
505         }
506 }
507
508 int
509 issuesct0(Req *r0, Atatab *a, Dev *d)
510 {
511         char *s;
512         uchar proto;
513         Atatab *txa;
514         Req r;
515
516         if((d->feat & Dsct) == 0){
517                 eprint("sct not supported\n");
518                 return -1;
519         }
520
521         /* 1. issue command */
522         sctreq(&r);
523         r.data = malloc(r0->count);
524         memcpy(r.data, r0->data, r0->count);
525         r.count = r0->count;
526         fisset(&r, Fsc, 1);
527         fisset(&r, Flba0, 0xe0);
528         if(issueata(&r, sctissue, d) == -1)
529                 return -1;
530         if(s = sctrsp(&r)){
531                 eprint("sct error: %s\n", s);
532                 return -1;
533         }
534
535         /* 1a. check response */
536         if((s = sctready(d, 1)) != nil){
537                 eprint("sct cmd: %s\n", s);
538                 return -1;
539         }
540         /* 2. transfer data */
541
542         proto = a->protocol;
543         if(r0->fisbits & 1 << 16){
544                 proto &= ~Pdatam;
545                 proto |= r0->cmd.ataproto;
546         }
547         switch(proto & Pdatam){
548         default:
549                 txa = nil;
550                 break;
551         case Pin:
552                 txa = sctread;
553                 break;
554 /*      case Pout:
555                 txa = sctout;
556                 break;
557 */
558         }
559
560         if(txa != nil){
561                 sctreq(&r);
562                 r.count = 512;
563                 fisset(&r, Fsc, 1);
564                 fisset(&r, Flba0, 0xe1);
565                 if(issueata(&r, txa, d) == -1)
566                         return -1;
567
568                 /* 2a. check response */
569                 if((s = sctready(d, 1)) != nil){
570                         eprint("sct cmd: %s\n", s);
571                         return -1;
572                 }
573         }
574
575         sctout((ushort*)r0->data, &r);
576         free(r.data);
577         return 0;
578 }
579
580 static void*
581 pushtrace(int i)
582 {
583         void *tr0;
584
585         tr0 = malloc(sizeof issuetr);
586         if(tr0 == 0)
587                 return 0;
588         memcpy(tr0, issuetr, sizeof issuetr);
589         memset(issuetr, i, sizeof issuetr);
590         return tr0;
591 }
592
593 static void
594 poptrace(void *tr0)
595 {
596         if(tr0 == nil)
597                 return;
598         memcpy(issuetr, tr0, sizeof issuetr);
599         free(tr0);
600 }
601
602 int
603 issuesct(Req *r0, Atatab *a, Dev *d)
604 {
605         int r;
606         void *t;
607
608         t = nil;
609         if(scttrace)
610                 t = pushtrace(1);
611         r = issuesct0(r0, a, d);
612         if(scttrace)
613                 poptrace(t);
614         return r;
615 }
616
617 int
618 issue(Req *r, Atatab *a, Dev *d)
619 {
620         int rv;
621         int (*f)(Req*, Atatab*, Dev*);
622
623         if(a->protocol & Psct)
624                 f = issuesct;
625         else if((a->protocol & Pprotom) == Ppkt)
626                 f = issuepkt;
627         else
628                 f = issueata;
629         rv = f(r, a, d);
630         if(r->haverfis)
631         if(r->reply.fis[Fstatus] & ASerr){
632                 werrstr("ata error");
633                 rv = -1;
634         }
635         return rv;
636 }
637
638 void
639 sigfmt(Req *r)
640 {
641         print("%.8ux\n", fistosig(r->reply.fis));
642 }
643
644 int
645 opendev(char *dev, Dev *d)
646 {
647         char buf[128];
648         int rv;
649         ushort *u;
650         Req r;
651
652         if(d->fd != -1)
653                 close(d->fd);
654         memset(d, 0, sizeof *d);
655         snprint(buf, sizeof buf, "%s/raw", dev);
656         d->fd = open(buf, ORDWR);
657         if(d->fd == -1)
658                 return -1;
659         memset(&r, 0, sizeof r);
660         if(issue(&r, sigcmd, d) == -1){
661 lose:
662                 close(d->fd);
663                 return -1;
664         }
665         setfissig(d, fistosig(r.reply.fis));
666         memset(&r, 0, sizeof r);
667         r.count = 512;
668         r.nsect = 1;
669         if(d->sig>>16 == 0xeb14)
670                 rv = issue(&r, idpktcmd, d);
671         else
672                 rv = issue(&r, idcmd, d);
673         if(rv == -1)
674                 goto lose;
675         u = (ushort*)r.data;
676         d->nsect = idfeat(d, u);
677         d->secsize = idss(d, u);
678         d->wwn = idwwn(d, u);
679         return 0;
680 }
681
682 void
683 rawout(Req *r)
684 {
685         int n;
686
687         n = write(r->wfd, r->data, r->count);
688         if(n != r->count)
689                 eprint("!short write %ud wanted %lld\n", n, r->count);
690 }
691
692 static ushort
693 gbit16(void *a)
694 {
695         ushort j;
696         uchar *i;
697
698         i = a;
699         j  = i[1] << 8;
700         j |= i[0];
701         return j;
702 }
703
704 static Btab extra[] = {
705         12,     "ncqpri",
706         11,     "ncqunload",
707         10,     "phyevent",
708         9,      "hpwrctl",
709         3,      "6.0gbit",
710         2,      "3.0gbit",
711         1,      "1.5gbit",
712 };
713
714 static Btab suptab[] = {
715         8,      "wwn",
716         5,      "mediaserial",
717         1,      "smartst",
718         0,      "smartlog"
719 };
720
721 char*
722 pextraid(char *p, char *e, ushort *id, uint *medserial)
723 {
724         char *p0;
725         ushort u;
726
727         *p = 0;
728         *medserial = 0;
729         p0 = p;
730         p = sebtab(p, e, extra, nelem(extra), gbit16(id + 76));
731         if(p != p0)
732                 p = seprint(p, e, " ");
733         u = gbit16(id + 83);
734         if(u & 1<<5)
735                 p = seprint(p, e, "gpl ");
736         p0 = p;
737         p = sebtab(p, e, suptab, nelem(suptab), gbit16(id + 84));
738         if(p != p0)
739                 p = seprint(p, e, " ");
740         u = gbit16(id + 120);
741         if(u & 1<<2)
742                 p = seprint(p, e, "wunc ");
743         return p;
744 }
745
746 static char *patatab[] = {
747         "ata8-apt",
748         "ata/atapi-7",
749 };
750
751 static char *satatab[] = {
752         "ata8-ast",
753         "sata1.0a",
754         "sataiiext",
755         "sata2.5",
756         "sata2.6",
757         "sata3.0",
758 };
759
760 char*
761 ptransport(char *p, char *e, ushort *id)
762 {
763         char *s;
764         ushort u, i;
765
766         u = gbit16(id + 222);
767         if(u == 0 || u == 0xffff)
768                 return seprint(p, e, "unreported ");
769         i = (u>>5) & 0x7f;
770         switch(u & 7<<12){
771         default:
772                 s = "unktransport";
773                 break;
774         case 0:
775                 s = "unkparallel";
776                 if(i < nelem(patatab))
777                         s = patatab[i];
778                 break;
779         case 1<<12:
780                 s = "unkserial";
781                 if(i < nelem(satatab))
782                         s = satatab[i];
783                 break;
784         }
785         return seprint(p, e, "%s ", s);
786 }
787
788 Btab entab[] = {
789         10,     "hpa",
790         9,      "reset",
791         8,      "service",
792         7,      "release",
793         6,      "rdlookahd",
794         5,      "vwc",
795         4,      "packet",
796         3,      "pm",
797         2,      "security",
798         1,      "smart",
799 };
800
801 Btab addlen[] = {
802         15,     "cfast",
803 //      14,     "trim", /* check 169 */
804         13,     "lpsalignerr",
805         12,     "iddma",
806         11,     "rbufdma",
807         10,     "wbufdma",
808         9,      "pwddma",
809         8,      "dlmcdma",
810 };
811
812 char*
813 penabled(char *p, char *e, ushort *id)
814 {
815         char *p0;
816         ushort u;
817
818         p0 = p;
819         p = sebtab(p, e, addlen, nelem(addlen), gbit16(id + 69));
820         u = gbit16(id + 87);
821         if(u>>14 == 1){
822                 if(p != p0)
823                         p = seprint(p, e, " ");
824                 p = sebtab(p, e, entab, nelem(entab), gbit16(id + 85));
825         }
826         return p;
827 }
828
829 static char *fftab[] = {
830         nil,
831         "5¼",
832         "3½",
833         "2½",
834         "1.8",
835         "<1.8",
836 };
837
838 char*
839 pff(char *p, char *e, ushort *id)
840 {
841         char *p0;
842         ushort u;
843
844         p0 = p;
845         u = gbit16(id + 168);
846         if(u < nelem(fftab) && fftab[u] != nil)
847                 p = seprint(p, e, "%s ", fftab[u]);
848         u = gbit16(id + 217);
849         if(u == 1)
850                 p = seprint(p, e, "solid-state ");
851         else if(u != 0 && u != 0xfffe)
852                 p = seprint(p, e, "%udrpm ", u);
853         if(p != p0)
854                 p--;
855         *p = 0;
856         return p;
857 }
858
859 Btab scttab[] = {
860         5,      "tables",
861         4,      "feactl",
862         3,      "errctl",
863         2,      "wsame",
864         1,      "rwlong",
865         0,      "sct",
866 };
867
868 char*
869 psct(char *p, char *e, ushort *id)
870 {
871         return sebtab(p, e, scttab, nelem(scttab), gbit16(id + 206));
872 }
873
874 void
875 idfmt(Req *r)
876 {
877         char buf[100];
878         uint ss, i;
879         ushort *id;
880         uvlong nsect;
881         Sfis f;
882
883         if(r->fmtrw == 0){
884                 rawout(r);
885                 return;
886         }
887         id = (ushort*)r->data;
888         nsect = idfeat(&f, id);
889         ss = idss(&f, id);
890
891         idmove(buf, id+10, 20);
892         print("serial\t%s\n", buf);
893         idmove(buf, id+23, 8);
894         print("firm\t%s\n", buf);
895         idmove(buf, id+27, 40);
896         print("model\t%s\n", buf);
897         print("wwn\t%ullx\n", idwwn(&f, id));
898         pflag(buf, buf + sizeof buf, &f);
899         print("flags\t%s", buf);
900         print("geometry %llud %ud", nsect, ss);
901         if(f.c | f.h | f.s)
902                 print(" %ud %ud %ud", f.c, f.h, f.s);
903         print("\n");
904         penabled(buf, buf + sizeof buf, id);
905         print("enabled\t%s\n", buf);
906         pextraid(buf, buf + sizeof buf, id, &i);
907         print("extra\t%s\n", buf);
908         if(i){
909                 idmove(buf, id + 176, 60);
910                 if(buf[0] != 0)
911                         print("medias\t%s\n", buf);
912         }
913         psct(buf, buf + sizeof buf, id);
914         if(buf[0])
915                 print("sct\t%s\n", buf);
916         ptransport(buf, buf + sizeof buf, id);
917         print("trans\t%s\n", buf);
918         pff(buf, buf + sizeof buf, id);
919         if(buf[0])
920                 print("ff\t%s\n", buf);
921 }
922
923 void
924 smfmt(Req *r)
925 {
926         uchar *fis;
927
928         if(r->cmd.fis[Ffeat] == 0xda){
929                 fis = r->reply.fis;
930                 if(fis[5] == 0x4f &&
931                    fis[6] == 0xc2)
932                         eprint("normal\n");
933                 else
934                         eprint("threshold exceeded\n");
935                 return;
936         }
937 }
938
939 void
940 iofmt(Req *r)
941 {
942         uchar *u;
943         int i;
944
945         if(r->fmtrw == 0){
946                 rawout(r);
947                 return;
948         }
949         u = r->data;
950         for(i = 0; i < r->count; i += 16)
951                 fprint(2, "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux"
952                 "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux\n",
953                 u[i + 0], u[i + 1], u[i + 2], u[i + 3], u[i + 4], u[i + 5], u[i + 6], u[i + 7],
954                 u[i + 8], u[i + 9], u[i +10], u[i +11], u[i +12], u[i +13], u[i +14], u[i +15]);
955 }
956
957 static char *csbyte[] = {
958         "never started",
959         nil,
960         "competed without error",
961         "in progress",
962         "suspended by cmd from host",
963         "aborted by cmd from host",
964         "aborted by device with fatal error",
965 };
966
967 static char *exe[] = {
968         "no error or never run",
969         "aborted by host",
970         "interrupted by host",
971         "fatal error; unable to complete",
972         "failed",
973         "failed: electricial",
974         "failed: servo",
975         "failed: read",
976         "failed: shipping damage",
977 [0xf]   "in progress",
978 };
979
980 char*
981 tabtr(uint u, char **tab, int ntab)
982 {
983         char *s;
984
985         if(u >= ntab || (s = tab[u]) == nil)
986                 s = "reserved";
987         return s;
988 }
989
990 void
991 sdfmt(Req *r)
992 {
993         char *s;
994         uchar *b;
995         ushort u;
996
997         if(r->fmtrw == 0){
998                 rawout(r);
999                 return;
1000         }
1001         b = r->data;
1002         u = b[362];
1003         if((u & 0xf0) == 0x80 && u != 0x81 && u != 0x83)
1004                 u &= 0xf;
1005         s = tabtr(u, csbyte, nelem(csbyte));
1006         print("col status: %.2ux %s\n", b[362], s);
1007         u = b[363];
1008         s = tabtr(u>>4, exe, nelem(exe));
1009         if(u & 0xf)
1010                 print("exe status: %.2ux %s, %d0%% left\n", u, s, u & 0xf);
1011         else
1012                 print("exe status: %.2ux %s\n", u, s);
1013         u = b[364] | b[365]<<8;
1014         print("time left: %uds\n", u);
1015         print("shrt poll: %udm\n", b[373]);
1016         u = b[374];
1017         if(u == 0xff)
1018                 u = b[375] | b[376]<<8;
1019         print("ext poll: %udm\n", u);
1020 }
1021
1022 void
1023 pagemapfmt(Req *r)
1024 {
1025         int i;
1026         ushort *u;
1027
1028         u = (ushort*)r->data;
1029         if(u[0] != 1){
1030                 print("unsupported\n");
1031                 return;
1032         }
1033         for(i = 1; i < 128; i++)
1034                 if(u[i] > 0)
1035                         print("page %d: %d\n", i, u[i]);
1036 }
1037
1038 void
1039 slfmt(Req *r)
1040 {
1041         switch(r->cmd.fis[Flba0]){
1042         default:
1043                 iofmt(r);
1044                 break;
1045         case 0:
1046                 pagemapfmt(r);
1047                 break;
1048         }
1049 }
1050
1051 enum{
1052         Physz   = 7<<12,
1053 };
1054
1055 static char *phyec[] = {
1056         "no event",
1057         "icrc",
1058         "err data",
1059         "err d2h data",
1060         "err h2d data",
1061 [0x05]  "err nd",
1062         "err d2h nd",
1063         "err h2d nd",
1064         "retry d2h nd",
1065         "nready",
1066 [0x0a]  "comreset",
1067         "h2d crc",
1068         nil,
1069         "bad h2d",
1070         nil,
1071         "err h2d data crc",
1072 [0x10]  "err h2d data",
1073         nil,
1074         "err h2d nd crc",
1075         "err h2d nd",
1076 };
1077
1078 void
1079 phyfmt(Req *r)
1080 {
1081         char *ec;
1082         uchar *p;
1083         ushort *u, *e, id, sz;
1084
1085         u = (ushort*)r->data;
1086         e = u + 510/sizeof *u;
1087         for(u += 2; u < e; u += sz){
1088                 id = w((uchar*)u);
1089                 sz = (id & Physz) >> 12;
1090                 id &= ~Physz;
1091                 if(sz == 0)
1092                         break;
1093                 ec = "unk";
1094                 if(id < nelem(phyec) && phyec[id] != nil)
1095                         ec = phyec[id];
1096                 print("%.4ux\t%-15s\t", id, ec);
1097                 p = (uchar*)u + 2;
1098                 switch(sz<<1){
1099                 default:
1100                         print("\n");
1101                         break;
1102                 case 2:
1103                         print("%.4ux\n", w(p));
1104                         break;
1105                 case 4:
1106                         print("%.8ux\n", dw(p));
1107                         break;
1108                 case 8:
1109                         print("%.16llux\n", qw(p));
1110                         break;
1111                 }
1112                 sz += 1;
1113         }
1114 }
1115
1116 typedef struct Gltab Gltab;
1117 struct Gltab{
1118         int     offset;
1119         char    *name;
1120 };
1121
1122 Gltab page3[] = {
1123         8,      "power-on hrs",
1124         16,     "head flying hrs",
1125         24,     "head loads",
1126         32,     "realloc'd sec",
1127         40,     "read recovery att",
1128         48,     "start failures"
1129 };
1130         
1131 void
1132 qpfmt(Req *r, Gltab *t, int ntab)
1133 {
1134         uchar *u;
1135         int i;
1136         uvlong v;
1137
1138         u = r->data;
1139         for(i = 0; i < ntab; i++){
1140                 v = qw(u + t[i].offset);
1141                 if((v & 3ll<<63) != 3ll<<63)
1142                         continue;
1143                 print("%lud\t%s\n", (ulong)v, t[i].name);
1144         }
1145 }
1146
1147 static char *sctsttab[] = {
1148         "active waiting",
1149         "standby",
1150         "sleep",
1151         "dst bgnd",
1152         "smart bgnd",
1153         "sct bgnd",
1154 };
1155
1156 void
1157 sctstatfmt(Req *r)
1158 {
1159         char *s;
1160         uchar *id, c;
1161
1162         id = r->data;
1163         print("version\t%d\n", gbit16(id + 0));
1164         print("vnd ver\t%2ux\n", gbit16(id + 2));
1165         print("flags\t%.8ux\n", dw(id + 6));
1166         c = id[10];
1167         s = "unk";
1168         if(c < nelem(sctsttab))
1169                 s = sctsttab[c];
1170         print("state\t%s\n", s);
1171         print("ext stat\t%.4ux\n", gbit16(id + 14));
1172         print("act code\t%.4ux\n", gbit16(id + 16));
1173         print("fn code\t%.4ux\n", gbit16(id + 18));
1174         print("lba\t%llud\n", qw(id + 40));
1175         print("temp\t%d\n", id[200]);
1176         print("min t\t%d %d\n", id[201], id[203]);
1177         print("max t\t%d %d\n", id[202], id[204]);
1178         print("ot\t%d\n", dw(id + 206));
1179         print("ut\t%d\n", dw(id + 210));
1180 }
1181
1182
1183 void
1184 glfmt(Req *r)
1185 {
1186         switch(r->cmd.fis[Flba0]){
1187         case 0:
1188                 pagemapfmt(r);
1189                 break;
1190         case 3:
1191                 qpfmt(r, page3, nelem(page3));
1192                 break;
1193         case 17:
1194                 phyfmt(r);
1195                 break;
1196         case 0xe0:
1197                 sctstatfmt(r);
1198                 break;
1199         default:
1200                 iofmt(r);
1201                 break;
1202         }
1203 }
1204
1205 char*
1206 readline(char *prompt, char *line, int len)
1207 {
1208         char *p, *e, *q;
1209         int n, dump;
1210
1211         e = line + len;
1212 retry:
1213         dump = 0;
1214         if(interrupted)
1215                 eprint("\n%s", prompt);
1216         else
1217                 eprint("%s", prompt);
1218         interrupted = 0;
1219         for(p = line;; p += n){
1220                 if(p == e){
1221                         dump = 1;
1222                         p = line;
1223                 }
1224                 n = read(0, p, e - p);
1225                 if(n < 0){
1226                         if(interrupted)
1227                                 goto retry;
1228                         return nil;
1229                 }
1230                 if(n == 0)
1231                         return nil;
1232                 if(q = memchr(p, '\n', n)){
1233                         if(dump){
1234                                 eprint("!line too long\n");
1235                                 goto retry;
1236                         }
1237                         p = q;
1238                         break;
1239                 }
1240         }
1241         *p = 0;
1242         return line;
1243 }
1244
1245 void
1246 suggesttab(char *cmd, Atatab *a, int n)
1247 {
1248         int i, l;
1249
1250         l = strlen(cmd);
1251         for(i = 0; i < n; i++)
1252                 if(cistrncmp(cmd, a[i].name, l) == 0)
1253                         eprint("%s\n", a[i].name);
1254 }
1255
1256 Atatab*
1257 findtab(char **cmd, Atatab *a, int n)
1258 {
1259         char *p, *c;
1260         int i, cc, max, l;
1261
1262         cc = strtoul(*cmd, &p, 0);
1263         if(p != *cmd && (*p == 0 || *p == ' ')){
1264                 for(i = 0; i < n; i++)
1265                         if(a[i].cc == cc){
1266                                 *cmd = p + 1;
1267                                 return a + cc;
1268                         }
1269                 return 0;
1270         }
1271         max = 0;
1272         cc = 0;
1273         c = *cmd;
1274         for(i = 0; i < n; i++){
1275                 l = strlen(a[i].name);
1276                 if(l > max && cistrncmp(*cmd, a[i].name, l) == 0)
1277                 if(c[l] == ' ' || c[l] == 0){
1278                         max = l + (c[l] == ' ');
1279                         cc = i;
1280                 }
1281         }
1282         if(max > 0){
1283                 *cmd = *cmd + max;
1284                 return a + cc;
1285         }
1286         return 0;
1287 }
1288                 
1289 int
1290 catch(void*, char *note)
1291 {
1292         if(strstr(note, "interrupt") != nil)
1293                 return interrupted = 1;
1294         return 0;
1295 }
1296
1297 char**
1298 ndargs(Atatab*, Req *, char **p)
1299 {
1300         return p;
1301 }
1302
1303 char**
1304 ioargs(Atatab *, Req *r, char **p)
1305 {
1306         if(r->nsect == 0)
1307                 r->nsect = 1;
1308         if(p[0] == 0)
1309                 return p;
1310         r->lba = strtoull(p[0], 0, 0);
1311         p++;
1312         if(p[0] == 0)
1313                 return p;
1314         r->nsect = strtoul(p[0], 0, 0);
1315         return p + 1;
1316 }
1317
1318 char**
1319 stdargs(Atatab *, Req *r, char **p)
1320 {
1321         char *s;
1322         Rune x;
1323
1324         for(; p[0] && p[0][0] == '-' && p[0][1]; p++){
1325                 s = p[0] + 1;
1326                 if(*s == '-'){
1327                         p++;
1328                         break;
1329                 }
1330                 while(*s && (s += chartorune(&x, s)))
1331                 switch(x){
1332                 case 'r':
1333                         r->raw = 1;
1334                         break;
1335                 default:
1336                         return p;
1337                 }
1338         }
1339         return p;
1340 }
1341
1342 static void
1343 chopoff(char *s, char *extra)
1344 {
1345         char *p;
1346         int l, ls;
1347
1348         l = strlen(extra);
1349         ls = strlen(s);
1350         if(l >= ls)
1351                 return;
1352         p = s + ls - l;
1353         if(strcmp(p, extra) == 0)
1354                 *p = 0;
1355 }
1356
1357 char*
1358 trim(char *s)
1359 {
1360         char *p;
1361
1362         while(*s && (*s == ' ' || *s == '\t'))
1363                 s++;
1364         if(*s == 0)
1365                 return nil;
1366         p = s + strlen(s) - 1;
1367         while(*p == ' ' || *p == '\t')
1368                 p--;
1369         p[1] = 0;
1370         return s;
1371 }
1372
1373 int
1374 doredir(Req *r, char **f, int nf, int mode, int *fd1, int *fd2)
1375 {
1376         int fd;
1377
1378         if(nf != 1 && nf != 2){
1379                 eprint("!args\n");
1380                 return -1;
1381         }
1382         fd = -1;
1383         if(nf == 2){
1384                 fd = open(f[1], mode);
1385                 if(mode != OREAD){
1386                         if(fd == -1)
1387                                 fd = create(f[1], mode, 0660);
1388                         else
1389                                 seek(fd, 0, 2);
1390                 }
1391         }
1392         if(fd1){
1393                 close(*fd1);
1394                 *fd1 = fd;
1395         }
1396         if(fd2){
1397                 r->fmtrw = fd == -1;
1398                 close(*fd2);
1399                 *fd2 = fd;
1400         }
1401         return fd;
1402 }
1403
1404 int
1405 special(char *s, Dev *d, Req *r)
1406 {
1407         char buf[512], path[128], *f[20], sbuf[512], s2[512], *p, *e, *t;
1408         uchar *u;
1409         int i, j, nf;
1410         Atatab *a;
1411
1412         p = buf;
1413         e = buf + sizeof buf;
1414         if(!strcmp(s, "close")){
1415                 r->haverfis = 0;
1416                 close(d->fd);
1417                 d->fd = -1;
1418                 return 0;
1419         }
1420         if(!strcmp(s, "scttrace")){
1421                 scttrace = 1;
1422                 return 0;
1423         }
1424         if(!strcmp(s, "dev")){
1425                 if(d->fd == -1){
1426                         eprint("!bad cmd (device closed)\n");
1427                         return 0;
1428                 }
1429                 if(fd2path(d->fd, path, sizeof path) == -1)
1430                         sysfatal("fd2path: %r");
1431                 chopoff(path, "/raw");
1432                 p = seprint(p, e, "dev\t%s\n", path);
1433                 p = seprint(p, e, "flags\t");
1434                 p = pflag(p, e, d);
1435                 p = seprint(p, e, "lsectsz\t" "%ud ptol %ud\n", d->lsectsz, 1<<d->physshift);
1436                 p = seprint(p, e, "geometry %llud %ud\n", d->nsect, d->secsize);
1437                 if(d->c | d->h | d->s)
1438                         seprint(p, e, "chs\t%d %d %d\n", d->c, d->h, d->s);
1439                 print("%s", buf);
1440                 return 0;
1441         }
1442         if(!strcmp(s, "help")){
1443                 suggesttab(buf, atatab, nelem(atatab));
1444                 return 0;
1445         }
1446         if(!strcmp(s, "probe")){
1447                 probe();
1448                 return 0;
1449         }
1450         if(!strcmp(s, "rfis")){
1451                 if(r->haverfis == 0){
1452                         eprint("!no rfis\n");
1453                         return 0;
1454                 }
1455                 p = seprint(p, e, "%.2x\n", r->reply.sdcmd);
1456                 u = r->reply.fis;
1457                 for(i = 0; i < 16; i++)
1458                         p = seprint(p, e, "%.2ux", u[i]);
1459                 seprint(p, e, "\n");
1460                 print("%s", buf);
1461                 return 0;
1462         }
1463         for(t = s; *t == '<' || *t == '>'; t++)
1464                 ;
1465         if(t != s)
1466                 snprint(sbuf, sizeof buf, "%.*s %s", utfnlen(s, t - s), s, t);
1467         else
1468                 snprint(sbuf, sizeof sbuf, "%s", s);
1469         nf = tokenize(sbuf, f, nelem(f));
1470         if(!strcmp(f[0], "issuetr")){
1471                 if(nf == 1)
1472                         for(i = 0; i < nelem(issuetr); i++)
1473                                 issuetr[i] ^= 1;
1474                 else{
1475                         p = s2;
1476                         e = s2 + sizeof s2;
1477                         for(i = 1; i < nf - 1; i++)
1478                                 p = seprint(p, e, "%s ", f[i]);
1479                         p = seprint(p, e, "%s", f[i]);
1480                         e = s2;
1481                         for(i = 1; i < nf; i++){
1482                                 j = strtoul(f[i], &p, 0);
1483                                 if(*p == 0 && j < nelem(issuetr))
1484                                         issuetr[i] ^= 1;
1485                                 else if(a = findtab(&e, atatab, nelem(atatab)))
1486                                         issuetr[a->cc & 0xff] ^= 1;
1487                         }
1488                 }
1489                 return 0;
1490         }
1491         if(!strcmp(f[0], "open")){
1492                 r->lba = 0;
1493                 if(nf == 2)
1494                         opendev(f[1], d);
1495                 else
1496                         eprint("!bad args to open\n");
1497                 return 0;
1498         }
1499         if(!strcmp(f[0], ">")){
1500                 doredir(r, f, nf, OWRITE, 0, &r->wfd);
1501                 return 0;
1502         }
1503         if(!strcmp(f[0], "<")){
1504                 doredir(r, f, nf, OREAD, &r->rfd, 0);
1505                 return 0;
1506         }
1507         if(!strcmp(f[0], "<>")){
1508                 doredir(r, f, nf, OWRITE, &r->rfd, &r->wfd);
1509                 return 0;
1510         }
1511         return -1;
1512 }
1513
1514 void
1515 setreg(Req *r, uint reg, uvlong v)
1516 {
1517         uchar *o;
1518         int x;
1519
1520         switch(reg & (Sbase | Pbase)){
1521         case 0:
1522                 r->fisbits |= 1 << reg;
1523                 r->cmd.fis[reg] = v;
1524                 break;
1525         case Sbase:
1526         case Sbase | Pbase:
1527                 x = reg & ~(Sbase | Ssz);
1528                 o = r->data + x*2;
1529                 assert(x < r->count);
1530                 switch(reg & Ssz){
1531                 default:
1532                         print("reg & Ssz %ux\n", reg & Ssz);
1533                         _assert("bad table");
1534                 case Sw:
1535                         pw(o, v);
1536                         break;
1537                 case Sdw:
1538                         pdw(o, v);
1539                         break;
1540                 case Sqw:
1541                         pqw(o, v);
1542                         break;
1543                 }
1544                 break;
1545         case Pbase:
1546                 /* fix me please: this is teh suck */
1547                 r->fisbits |= 1 << 16;
1548                 r->cmd.ataproto = v;
1549                 break;
1550         }
1551 }
1552
1553 int
1554 setfis0(Req *r, Txtab *t, char *p)
1555 {
1556         char *e;
1557         uvlong v;
1558
1559         v = strtoull(p, &e, 0);
1560         setreg(r, t->val, v);
1561         return *e != 0;
1562 }
1563
1564 char**
1565 setfis(Atatab*, Req *r, char **p)
1566 {
1567         char *s;
1568         int i;
1569
1570 loop:
1571         if((s = p[0]) == 0)
1572                 return p;
1573         for(i = 0; i < nelem(regtx); i++)
1574                 if(strcmp(s, regtx[i].name) == 0 && p[1] != nil){
1575 //                      print("setfis0 %s %s\n", p[0], p[1]);
1576                         setfis0(r, regtx + i, p[1]);
1577                         p += 2;
1578                         goto loop;
1579                 }
1580         return p;
1581 }
1582
1583 char*
1584 rname(char *buf, int n, int r)
1585 {
1586         int i;
1587
1588         for(i = 0; i < nelem(regtx); i++)
1589                 if(regtx[i].val == r){
1590                         snprint(buf, n, "%s", regtx[i].name);
1591                         return buf;
1592                 }
1593         snprint(buf, n, "%.2ux", r);
1594         return buf;
1595 }
1596
1597 int
1598 mwcmp(char *a, char ***l)
1599 {
1600         char buf[128], *f[20], **p;
1601         int nf, i;
1602
1603         if(*a == 0)
1604                 return 0;
1605         p = *l;
1606         if(p[0] == 0)
1607                 return -1;
1608         snprint(buf, sizeof buf, "%s", a);
1609         nf = tokenize(buf, f, nelem(f));
1610         for(i = 0; i < nf; i++)
1611                 if(p[i] == nil || cistrcmp(p[i], f[i]) != 0)
1612                         return -1;
1613         *l = p + i - 1;
1614         return 0;
1615 }
1616
1617 char **dofetab(Fetab*, Req*, char**);
1618
1619 static char hexdig[] = "ABCDEFabcdef0123456789";
1620 static char hexonly[] = "ABCDEFabcdef";
1621 static char Enum[] = "expecting number";
1622
1623 int
1624 fenum(Fetab *, int v, char ***p)
1625 {
1626         char *e, *s, *r;
1627         int base;
1628
1629         if(v >= 0)
1630                 return v;
1631         s = *(*p + 1);
1632         e = nil;
1633         if(s == nil || *s == 0)
1634                 e = Enum;
1635         else{
1636                 base = 0;
1637                 if(strspn(s, hexdig) == strlen(s) &&
1638                 strpbrk(s, hexonly) != nil)
1639                         base = 0x10;
1640                 v = strtoul(s, &r, base);
1641                 if(*r)
1642                         e = Enum;
1643         }
1644         if(e == nil)
1645                 (*p)++;
1646         else
1647                 print("error: %s [%s]\n", e, s);
1648         return v;
1649 }
1650
1651 char**
1652 dofetab0(Fetab *t, Req *r, char **p)
1653 {
1654         int i, v;
1655         Txtab *tab;
1656
1657         if(t == nil)
1658                 return p;
1659         tab = t->tab;
1660 loop:
1661         for(i = 0; i < t->ntab; i++)
1662                 if(mwcmp(tab[i].name, &p) == 0){
1663                         v = fenum(t, tab[i].val, &p);
1664                         setreg(r, t->reg, v);
1665                         if(tab[i].name[0] != 0){
1666                                 p = dofetab(tab[i].fe, r, p + 1);
1667                                 goto loop;
1668                         }
1669                 }
1670         return p;
1671
1672 }
1673
1674 char**
1675 dofetab(Fetab *t, Req *r, char **p)
1676 {
1677         for(; t != nil && t->ntab > 0; t++)
1678                 p = dofetab0(t, r, p);
1679         return p;
1680 }
1681
1682 char**
1683 dotab(Atatab *a, Req *r, char **p)
1684 {
1685         if(a->tab == nil)
1686                 return p;
1687         return dofetab(a->tab, r, p);
1688 }
1689
1690 void
1691 initreq(Req *r)
1692 {
1693         memset(r, 0, sizeof *r);
1694 //      r->wfd = open("/dev/null", OWRITE);
1695         r->wfd = dup(1, -1);
1696         if(rflag == 0)
1697                 r->fmtrw = 1;
1698         r->rfd = open("/dev/zero", OREAD);
1699 }
1700
1701 void
1702 setup(void)
1703 {
1704         int i;
1705
1706         for(i = 0; i < nelem(atatab); i++)
1707                 if(atatab[i].cc == 0x2f){
1708                         sctread = atatab + i;
1709                         break;
1710                 }
1711         for(; i < nelem(atatab); i++)
1712                 if(atatab[i].cc == 0x3f){
1713                         sctissue = atatab + i;
1714                         break;
1715                 }
1716         for(; i < nelem(atatab); i++)
1717                 if(atatab[i].cc == 0xa1){
1718                         idpktcmd = atatab + i;
1719                         break;
1720                 }
1721         for(; i < nelem(atatab); i++)
1722                 if(atatab[i].cc == 0xec){
1723                         idcmd = atatab + i;
1724                         break;
1725                 }
1726         for(; i < nelem(atatab); i++)
1727                 if(atatab[i].cc == 0xf000){
1728                         sigcmd = atatab + i;
1729                         break;
1730                 }
1731 }
1732
1733 typedef struct Htab Htab;
1734 struct Htab {
1735         ulong   bit;
1736         char    *name;
1737 };
1738
1739 Htab ertab[] = {
1740         Eicrc,  "icrc",
1741         Ewp,    "wp",
1742         Emc,    "mc",
1743         Eidnf,  "idnf",
1744         Emcr,   "mcr",
1745         Eabrt,  "abrt",
1746         Enm,    "nm",
1747         Emed,   "med",
1748         Eunc,   "unc",
1749 };
1750
1751 Htab sttab[] = {
1752         ASbsy,  "bsy",
1753         ASdrdy, "drdy",
1754         ASdf,   "df",
1755         ASdrq,  "drq",
1756         ASerr,  "err",
1757 };
1758
1759 static char*
1760 htabfmt(char *p, char *e, Htab *t, int n, ulong u)
1761 {
1762         char *p0;
1763         uint i;
1764
1765         p0 = p;
1766         for(i = 0; i < n; i++)
1767                 if(u & t[i].bit)
1768                         p = seprint(p, e, "%s | ", t[i].name);
1769         if(p - 3 >= p0)
1770                 p -= 3;
1771         if(p < e)
1772                 p[0] = 0;
1773         return p;
1774 }
1775
1776 void
1777 prerror(Req *r)
1778 {
1779         char st[64], er[64];
1780         uchar *u;
1781
1782         u = r->reply.fis;
1783         if(r->haverfis == 0 ||  (u[Fstatus] & ASerr) == 0)
1784                 return;
1785         htabfmt(er, er + sizeof er, ertab, nelem(ertab), u[Frerror]);
1786         htabfmt(st, st + sizeof st, sttab, nelem(sttab), u[Fstatus] & ~ASobs);
1787         fprint(2, "err %.2ux %.2ux (%s, %s)\n", u[Frerror], u[Fstatus], er, st);
1788 }
1789
1790 void
1791 usage(void)
1792 {
1793         eprint("usage: atazz dev\n");
1794         eprint(" or -c cmd\n");
1795         exits("usage");
1796 }
1797
1798 void
1799 main(int argc, char **argv)
1800 {
1801         char buf[1024], *p, *f[20], **fp;
1802         int nf, cflag, i;
1803         Atatab *a;
1804         Req r;
1805         Dev d;
1806
1807         cflag = 0;
1808         ARGBEGIN{
1809         case 'c':
1810                 cflag = atoi(EARGF(usage()));
1811                 break;
1812         case 'r':
1813                 rflag = 1;
1814                 break;
1815         default:
1816                 usage();
1817         }ARGEND
1818
1819         if(cflag){
1820                 for(i = 0; i < nelem(atatab); i++)
1821                         if(atatab[i].cc == cflag)
1822                                 print("%s\n", atatab[i].name);
1823                 exits("");
1824         }
1825
1826         setup();
1827         fmtinstall(L'π', πfmt);
1828         if(argc > 1)
1829                 usage();
1830         initreq(&r);
1831         d.fd = -1;
1832         if(argc == 1 && opendev(*argv, &d) == -1)
1833                 sysfatal("opendev: %r");
1834         atnotify(catch, 1);
1835         for(;;){
1836                 memset(&r.cmd, 0, sizeof r.cmd);
1837                 r.fisbits = 0;
1838                 if(readline("az> ", buf, sizeof buf-1) == nil)
1839                         break;
1840                 if((p = trim(buf)) == nil)
1841                         continue;
1842                 if(special(buf, &d, &r) == 0)
1843                         continue;
1844                 if(d.fd == -1){
1845                         eprint("!bad cmd (device closed)\n");
1846                         continue;
1847                 }
1848                 a = findtab(&p, atatab, nelem(atatab));
1849                 if(!a){
1850                         suggesttab(buf, atatab, nelem(atatab));
1851                         eprint("!unknown cmd\n");
1852                         continue;
1853                 }
1854                 nf = tokenize(p, f, nelem(f) - 1);
1855                 f[nf] = 0;
1856                 fp = stdargs(a, &r, f);
1857                 fp = setfis(a, &r, fp);
1858                 if(a->protocol & Psct){
1859                         r.count = 1 * 512;
1860                         r.data = realloc(r.data, r.count);
1861                         memset(r.data, 0, r.count);
1862                 }
1863                 fp = dotab(a, &r, fp);
1864                 switch(a->protocol & Pprotom){
1865                 default:
1866                         eprint("!bad proto1 %.2ux\n", a->protocol & Pprotom);
1867                         continue;
1868                 case Pnd:
1869                         fp = ndargs(a, &r, fp);
1870                 case Preset:
1871                 case Pdiag:
1872                         r.count = 0;
1873                         r.lba = 0;
1874                         r.nsect = 0;
1875                         break;
1876                 case Ppio:
1877                 case Pdma:
1878                 case Pdmq:
1879                 case Ppkt:
1880                         if(a->flags & Cmd5sc){
1881                                 r.nsect = r.cmd.fis[Fsc];
1882                                 if(r.nsect == 0)
1883                                         r.nsect = 1;
1884                                 r.cmd.fis[Fsc] = r.nsect;
1885                                 r.count = r.nsect * 0x200;
1886                         }else if((a->protocol & Pssm) == P512){
1887                                 r.lba = 0;
1888                                 r.nsect = 0;
1889                                 r.count = 512;
1890                         }else{
1891                                 fp = ioargs(a, &r, fp);
1892                                 r.count = d.secsize * r.nsect;
1893                         }
1894                         break;
1895                 }
1896                 if(fp[0]){
1897                         eprint("!extra args %π\n", fp);
1898                         continue;
1899                 }
1900                 if(issue(&r, a, &d) == -1){
1901                         prerror(&r);
1902                         continue;
1903                 }
1904                 if(a->fmt)
1905                         a->fmt(&r);
1906         }
1907         exits("");
1908 }