7 #pragma varargck argpos eprint 1
8 #pragma varargck type "π" char**
31 p = va_arg(f->args, char**);
33 return fmtstrcpy(f, "<nil**>");
43 eprint(char *fmt, ...)
53 n = vfprint(2, fmt, args);
59 fisset(Req *r, uint i, uint v)
72 print("%.2ux %.2ux\n", r->cmd.sdcmd, r->cmd.ataproto);
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]);
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]);
82 protostr(char *p, char *e, int pr)
88 p = seprint(p, e, "28:");
90 p = seprint(p, e, "28:");
114 p = seprint(p, e, "%s:", s);
126 p = seprint(p, e, "%s", s);
131 displaycmd(Req *r, Atatab *a)
136 if(a->cc > nelem(issuetr) || !issuetr[a->cc])
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]);
146 issueata(Req *r, Atatab *a, Dev *d)
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);
159 print("fisbits %.16b\n", r->fisbits);
161 r->cmd.ataproto = a->protocol;
163 fisset(r, 0, a->cc >> 8);
166 fisset(r, 1, Fiscmd);
170 if(r->rfd != Dontread){
171 n = readn(r->rfd, r->data, r->count);
174 eprint("!short src read %r\n");
176 eprint("!short src read %d wanted %lld\n", n, r->count);
182 if(0 && (d->feat & Dlba) == 0 && (d->c | d->h | d->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);
190 fisset(r, 6, c >> 8);
191 fisset(r, 7, Ataobs | h);
193 fisset(r, 4, r->lba);
194 fisset(r, 5, r->lba >> 8);
195 fisset(r, 6, r->lba >> 16);
197 if(pr == Pin || pr == Pout)
199 if((d->feat & Dllba) == 0)
200 u |= (r->lba >> 24) & 7;
202 fisset(r, 8, r->lba >> 24);
203 fisset(r, 9, r->lba >> 32);
204 fisset(r, 10, r->lba >> 48);
206 fisset(r, 12, r->nsect);
207 fisset(r, 13, r->nsect >> 8);
210 fisset(r, 7, Ataobs);
212 if(write(d->fd, &r->cmd, Cmdsz) != Cmdsz){
213 eprint("fis write error: %r\n");
220 ok = read(d->fd, "", 0) == 0;
223 ok = read(d->fd, r->data, r->count) == r->count;
227 ok = write(d->fd, r->data, r->count) == r->count;
233 eprint("xfer error: %.2ux %r\n", a->cc);
236 switch(n = read(d->fd, &r->reply, Replysz)){
241 eprint("status fis read error: %r\n");
244 eprint("status fis read error: short read: %d of %d\n", n, Replysz);
250 * cheezy code; just issue a inquiry. use scuzz
251 * for real work with atapi devices
254 issuepkt(Req *r, Atatab *a, Dev *d)
262 r->data = realloc(r->data, r->count);
263 if(r->data == nil && r->count > 0)
264 sysfatal("realloc: %r");
266 r->cmd.ataproto = a->protocol;
267 memset(r->cmd.fis, 0, Fissize);
274 if(write(d->fd, &r->cmd, 6 + 2) != 6 + 2){
275 eprint("fis write error: %r\n");
278 n = read(d->fd, r->data, r->count);
281 eprint("xfer error: %.2ux %r\n", a->cc);
285 print("n is %d (%lld)\n", n, r->count);
288 print("%.8s %.16s\n", p + 8, p + 16);
291 u = (uchar*)&r->reply;
292 n = read(d->fd, u, Replysz);
294 eprint("status fis read error (%d): %r\n", n);
299 memset(u + n, 0, Replysz - n);
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
313 memset(r, 0, sizeof *r);
325 if((r->reply.fis[Frerror] & (Eidnf | Eabrt)) == 0)
327 i = r->reply.fis[Fsc] | r->reply.fis[Flba0]<<8;
329 return "in progress";
331 snprint(buf, sizeof buf, "unknown %.2ux", r->reply.fis[Frerror]);
333 }else if(i < nelem(sctetab))
340 sctready(Dev *d, int sec)
345 static char e[ERRMAX];
354 fisset(&r, Flba0, 0xe0);
356 i = issueata(&r, sctread, d);
363 if((r.cmd.fis[Fsc] | r.cmd.fis[Fsc8]<<8) != 0xffff){
377 typedef struct Sttab Sttab;
402 for(i = 0; i < nelem(sctt); i++){
406 print("%s\t%d\n", sctt[i].name, c);
409 d = w(u + sctt[i].o);
410 print("%s\t%ud\n", sctt[i].name, d);
416 for(i = 0; i < n; i++){
417 c = u[34 + (l + i) % n];
419 snprint(buf, sizeof buf, "xx");
421 snprint(buf, sizeof buf, "%d", c);
424 print("\nt%d\t%d", i, c);
437 0x00010001, "set features", 0,
438 0x00010002, "enabled", 0,
439 0x00010003, "disabled", 0,
441 0x00020001, "enabled", 0,
442 0x00020002, "disabled", 0,
444 0x0003ffff, "minute", "minutes",
448 sctfcout(ushort *u, Req *r)
458 v = f[Fsc] | f[Flba0]<<8;
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);
468 v = f[Fsc] | f[Flba0]<<8;
478 scterout(ushort *u, Req *r)
486 v = f[Fsc] | f[Flba0]<<8;
493 sctout(ushort *u, Req *r)
509 issuesct0(Req *r0, Atatab *a, Dev *d)
516 if((d->feat & Dsct) == 0){
517 eprint("sct not supported\n");
521 /* 1. issue command */
523 r.data = malloc(r0->count);
524 memcpy(r.data, r0->data, r0->count);
527 fisset(&r, Flba0, 0xe0);
528 if(issueata(&r, sctissue, d) == -1)
531 eprint("sct error: %s\n", s);
535 /* 1a. check response */
536 if((s = sctready(d, 1)) != nil){
537 eprint("sct cmd: %s\n", s);
540 /* 2. transfer data */
543 if(r0->fisbits & 1 << 16){
545 proto |= r0->cmd.ataproto;
547 switch(proto & Pdatam){
564 fisset(&r, Flba0, 0xe1);
565 if(issueata(&r, txa, d) == -1)
568 /* 2a. check response */
569 if((s = sctready(d, 1)) != nil){
570 eprint("sct cmd: %s\n", s);
575 sctout((ushort*)r0->data, &r);
585 tr0 = malloc(sizeof issuetr);
588 memcpy(tr0, issuetr, sizeof issuetr);
589 memset(issuetr, i, sizeof issuetr);
598 memcpy(issuetr, tr0, sizeof issuetr);
603 issuesct(Req *r0, Atatab *a, Dev *d)
611 r = issuesct0(r0, a, d);
618 issue(Req *r, Atatab *a, Dev *d)
621 int (*f)(Req*, Atatab*, Dev*);
623 if(a->protocol & Psct)
625 else if((a->protocol & Pprotom) == Ppkt)
631 if(r->reply.fis[Fstatus] & ASerr){
632 werrstr("ata error");
641 print("%.8ux\n", fistosig(r->reply.fis));
645 opendev(char *dev, Dev *d)
654 memset(d, 0, sizeof *d);
655 snprint(buf, sizeof buf, "%s/raw", dev);
656 d->fd = open(buf, ORDWR);
659 memset(&r, 0, sizeof r);
660 if(issue(&r, sigcmd, d) == -1){
665 setfissig(d, fistosig(r.reply.fis));
666 memset(&r, 0, sizeof r);
669 if(d->sig>>16 == 0xeb14)
670 rv = issue(&r, idpktcmd, d);
672 rv = issue(&r, idcmd, d);
676 d->nsect = idfeat(d, u);
677 d->secsize = idss(d, u);
678 d->wwn = idwwn(d, u);
687 n = write(r->wfd, r->data, r->count);
689 eprint("!short write %ud wanted %lld\n", n, r->count);
704 static Btab extra[] = {
714 static Btab suptab[] = {
722 pextraid(char *p, char *e, ushort *id, uint *medserial)
730 p = sebtab(p, e, extra, nelem(extra), gbit16(id + 76));
732 p = seprint(p, e, " ");
735 p = seprint(p, e, "gpl ");
737 p = sebtab(p, e, suptab, nelem(suptab), gbit16(id + 84));
739 p = seprint(p, e, " ");
740 u = gbit16(id + 120);
742 p = seprint(p, e, "wunc ");
746 static char *patatab[] = {
751 static char *satatab[] = {
761 ptransport(char *p, char *e, ushort *id)
766 u = gbit16(id + 222);
767 if(u == 0 || u == 0xffff)
768 return seprint(p, e, "unreported ");
776 if(i < nelem(patatab))
781 if(i < nelem(satatab))
785 return seprint(p, e, "%s ", s);
803 // 14, "trim", /* check 169 */
813 penabled(char *p, char *e, ushort *id)
819 p = sebtab(p, e, addlen, nelem(addlen), gbit16(id + 69));
823 p = seprint(p, e, " ");
824 p = sebtab(p, e, entab, nelem(entab), gbit16(id + 85));
829 static char *fftab[] = {
839 pff(char *p, char *e, ushort *id)
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);
850 p = seprint(p, e, "solid-state ");
851 else if(u != 0 && u != 0xfffe)
852 p = seprint(p, e, "%udrpm ", u);
869 psct(char *p, char *e, ushort *id)
871 return sebtab(p, e, scttab, nelem(scttab), gbit16(id + 206));
887 id = (ushort*)r->data;
888 nsect = idfeat(&f, id);
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);
902 print(" %ud %ud %ud", f.c, f.h, f.s);
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);
909 idmove(buf, id + 176, 60);
911 print("medias\t%s\n", buf);
913 psct(buf, buf + sizeof buf, id);
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);
920 print("ff\t%s\n", buf);
928 if(r->cmd.fis[Ffeat] == 0xda){
934 eprint("threshold exceeded\n");
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]);
957 static char *csbyte[] = {
960 "competed without error",
962 "suspended by cmd from host",
963 "aborted by cmd from host",
964 "aborted by device with fatal error",
967 static char *exe[] = {
968 "no error or never run",
970 "interrupted by host",
971 "fatal error; unable to complete",
973 "failed: electricial",
976 "failed: shipping damage",
981 tabtr(uint u, char **tab, int ntab)
985 if(u >= ntab || (s = tab[u]) == nil)
1003 if((u & 0xf0) == 0x80 && u != 0x81 && u != 0x83)
1005 s = tabtr(u, csbyte, nelem(csbyte));
1006 print("col status: %.2ux %s\n", b[362], s);
1008 s = tabtr(u>>4, exe, nelem(exe));
1010 print("exe status: %.2ux %s, %d0%% left\n", u, s, u & 0xf);
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]);
1018 u = b[375] | b[376]<<8;
1019 print("ext poll: %udm\n", u);
1028 u = (ushort*)r->data;
1030 print("unsupported\n");
1033 for(i = 1; i < 128; i++)
1035 print("page %d: %d\n", i, u[i]);
1041 switch(r->cmd.fis[Flba0]){
1055 static char *phyec[] = {
1072 [0x10] "err h2d data",
1083 ushort *u, *e, id, sz;
1085 u = (ushort*)r->data;
1086 e = u + 510/sizeof *u;
1087 for(u += 2; u < e; u += sz){
1089 sz = (id & Physz) >> 12;
1094 if(id < nelem(phyec) && phyec[id] != nil)
1096 print("%.4ux\t%-15s\t", id, ec);
1103 print("%.4ux\n", w(p));
1106 print("%.8ux\n", dw(p));
1109 print("%.16llux\n", qw(p));
1116 typedef struct Gltab Gltab;
1124 16, "head flying hrs",
1126 32, "realloc'd sec",
1127 40, "read recovery att",
1128 48, "start failures"
1132 qpfmt(Req *r, Gltab *t, int ntab)
1139 for(i = 0; i < ntab; i++){
1140 v = qw(u + t[i].offset);
1141 if((v & 3ll<<63) != 3ll<<63)
1143 print("%lud\t%s\n", (ulong)v, t[i].name);
1147 static char *sctsttab[] = {
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));
1168 if(c < nelem(sctsttab))
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));
1186 switch(r->cmd.fis[Flba0]){
1191 qpfmt(r, page3, nelem(page3));
1206 readline(char *prompt, char *line, int len)
1215 eprint("\n%s", prompt);
1217 eprint("%s", prompt);
1219 for(p = line;; p += n){
1224 n = read(0, p, e - p);
1232 if(q = memchr(p, '\n', n)){
1234 eprint("!line too long\n");
1246 suggesttab(char *cmd, Atatab *a, int n)
1251 for(i = 0; i < n; i++)
1252 if(cistrncmp(cmd, a[i].name, l) == 0)
1253 eprint("%s\n", a[i].name);
1257 findtab(char **cmd, Atatab *a, int n)
1262 cc = strtoul(*cmd, &p, 0);
1263 if(p != *cmd && (*p == 0 || *p == ' ')){
1264 for(i = 0; i < n; i++)
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] == ' ');
1290 catch(void*, char *note)
1292 if(strstr(note, "interrupt") != nil)
1293 return interrupted = 1;
1298 ndargs(Atatab*, Req *, char **p)
1304 ioargs(Atatab *, Req *r, char **p)
1310 r->lba = strtoull(p[0], 0, 0);
1314 r->nsect = strtoul(p[0], 0, 0);
1319 stdargs(Atatab *, Req *r, char **p)
1324 for(; p[0] && p[0][0] == '-' && p[0][1]; p++){
1330 while(*s && (s += chartorune(&x, s)))
1343 chopoff(char *s, char *extra)
1353 if(strcmp(p, extra) == 0)
1362 while(*s && (*s == ' ' || *s == '\t'))
1366 p = s + strlen(s) - 1;
1367 while(*p == ' ' || *p == '\t')
1374 doredir(Req *r, char **f, int nf, int mode, int *fd1, int *fd2)
1378 if(nf != 1 && nf != 2){
1384 fd = open(f[1], mode);
1387 fd = create(f[1], mode, 0660);
1397 r->fmtrw = fd == -1;
1405 special(char *s, Dev *d, Req *r)
1407 char buf[512], path[128], *f[20], sbuf[512], s2[512], *p, *e, *t;
1413 e = buf + sizeof buf;
1414 if(!strcmp(s, "close")){
1420 if(!strcmp(s, "scttrace")){
1424 if(!strcmp(s, "dev")){
1426 eprint("!bad cmd (device closed)\n");
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");
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);
1442 if(!strcmp(s, "help")){
1443 suggesttab(buf, atatab, nelem(atatab));
1446 if(!strcmp(s, "probe")){
1450 if(!strcmp(s, "rfis")){
1451 if(r->haverfis == 0){
1452 eprint("!no rfis\n");
1455 p = seprint(p, e, "%.2x\n", r->reply.sdcmd);
1457 for(i = 0; i < 16; i++)
1458 p = seprint(p, e, "%.2ux", u[i]);
1459 seprint(p, e, "\n");
1463 for(t = s; *t == '<' || *t == '>'; t++)
1466 snprint(sbuf, sizeof buf, "%.*s %s", utfnlen(s, t - s), s, t);
1468 snprint(sbuf, sizeof sbuf, "%s", s);
1469 nf = tokenize(sbuf, f, nelem(f));
1470 if(!strcmp(f[0], "issuetr")){
1472 for(i = 0; i < nelem(issuetr); i++)
1477 for(i = 1; i < nf - 1; i++)
1478 p = seprint(p, e, "%s ", f[i]);
1479 p = seprint(p, e, "%s", f[i]);
1481 for(i = 1; i < nf; i++){
1482 j = strtoul(f[i], &p, 0);
1483 if(*p == 0 && j < nelem(issuetr))
1485 else if(a = findtab(&e, atatab, nelem(atatab)))
1486 issuetr[a->cc & 0xff] ^= 1;
1491 if(!strcmp(f[0], "open")){
1496 eprint("!bad args to open\n");
1499 if(!strcmp(f[0], ">")){
1500 doredir(r, f, nf, OWRITE, 0, &r->wfd);
1503 if(!strcmp(f[0], "<")){
1504 doredir(r, f, nf, OREAD, &r->rfd, 0);
1507 if(!strcmp(f[0], "<>")){
1508 doredir(r, f, nf, OWRITE, &r->rfd, &r->wfd);
1515 setreg(Req *r, uint reg, uvlong v)
1520 switch(reg & (Sbase | Pbase)){
1522 r->fisbits |= 1 << reg;
1523 r->cmd.fis[reg] = v;
1527 x = reg & ~(Sbase | Ssz);
1529 assert(x < r->count);
1532 print("reg & Ssz %ux\n", reg & Ssz);
1533 _assert("bad table");
1546 /* fix me please: this is teh suck */
1547 r->fisbits |= 1 << 16;
1548 r->cmd.ataproto = v;
1554 setfis0(Req *r, Txtab *t, char *p)
1559 v = strtoull(p, &e, 0);
1560 setreg(r, t->val, v);
1565 setfis(Atatab*, Req *r, char **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]);
1584 rname(char *buf, int n, int r)
1588 for(i = 0; i < nelem(regtx); i++)
1589 if(regtx[i].val == r){
1590 snprint(buf, n, "%s", regtx[i].name);
1593 snprint(buf, n, "%.2ux", r);
1598 mwcmp(char *a, char ***l)
1600 char buf[128], *f[20], **p;
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)
1617 char **dofetab(Fetab*, Req*, char**);
1619 static char hexdig[] = "ABCDEFabcdef0123456789";
1620 static char hexonly[] = "ABCDEFabcdef";
1621 static char Enum[] = "expecting number";
1624 fenum(Fetab *, int v, char ***p)
1633 if(s == nil || *s == 0)
1637 if(strspn(s, hexdig) == strlen(s) &&
1638 strpbrk(s, hexonly) != nil)
1640 v = strtoul(s, &r, base);
1647 print("error: %s [%s]\n", e, s);
1652 dofetab0(Fetab *t, Req *r, char **p)
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);
1675 dofetab(Fetab *t, Req *r, char **p)
1677 for(; t != nil && t->ntab > 0; t++)
1678 p = dofetab0(t, r, p);
1683 dotab(Atatab *a, Req *r, char **p)
1687 return dofetab(a->tab, r, p);
1693 memset(r, 0, sizeof *r);
1694 // r->wfd = open("/dev/null", OWRITE);
1695 r->wfd = dup(1, -1);
1698 r->rfd = open("/dev/zero", OREAD);
1706 for(i = 0; i < nelem(atatab); i++)
1707 if(atatab[i].cc == 0x2f){
1708 sctread = atatab + i;
1711 for(; i < nelem(atatab); i++)
1712 if(atatab[i].cc == 0x3f){
1713 sctissue = atatab + i;
1716 for(; i < nelem(atatab); i++)
1717 if(atatab[i].cc == 0xa1){
1718 idpktcmd = atatab + i;
1721 for(; i < nelem(atatab); i++)
1722 if(atatab[i].cc == 0xec){
1726 for(; i < nelem(atatab); i++)
1727 if(atatab[i].cc == 0xf000){
1728 sigcmd = atatab + i;
1733 typedef struct Htab Htab;
1760 htabfmt(char *p, char *e, Htab *t, int n, ulong u)
1766 for(i = 0; i < n; i++)
1768 p = seprint(p, e, "%s | ", t[i].name);
1779 char st[64], er[64];
1783 if(r->haverfis == 0 || (u[Fstatus] & ASerr) == 0)
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);
1793 eprint("usage: atazz dev\n");
1794 eprint(" or -c cmd\n");
1799 main(int argc, char **argv)
1801 char buf[1024], *p, *f[20], **fp;
1810 cflag = atoi(EARGF(usage()));
1820 for(i = 0; i < nelem(atatab); i++)
1821 if(atatab[i].cc == cflag)
1822 print("%s\n", atatab[i].name);
1827 fmtinstall(L'π', πfmt);
1832 if(argc == 1 && opendev(*argv, &d) == -1)
1833 sysfatal("opendev: %r");
1836 memset(&r.cmd, 0, sizeof r.cmd);
1838 if(readline("az> ", buf, sizeof buf-1) == nil)
1840 if((p = trim(buf)) == nil)
1842 if(special(buf, &d, &r) == 0)
1845 eprint("!bad cmd (device closed)\n");
1848 a = findtab(&p, atatab, nelem(atatab));
1850 suggesttab(buf, atatab, nelem(atatab));
1851 eprint("!unknown cmd\n");
1854 nf = tokenize(p, f, nelem(f) - 1);
1856 fp = stdargs(a, &r, f);
1857 fp = setfis(a, &r, fp);
1858 if(a->protocol & Psct){
1860 r.data = realloc(r.data, r.count);
1861 memset(r.data, 0, r.count);
1863 fp = dotab(a, &r, fp);
1864 switch(a->protocol & Pprotom){
1866 eprint("!bad proto1 %.2ux\n", a->protocol & Pprotom);
1869 fp = ndargs(a, &r, fp);
1880 if(a->flags & Cmd5sc){
1881 r.nsect = r.cmd.fis[Fsc];
1884 r.cmd.fis[Fsc] = r.nsect;
1885 r.count = r.nsect * 0x200;
1886 }else if((a->protocol & Pssm) == P512){
1891 fp = ioargs(a, &r, fp);
1892 r.count = d.secsize * r.nsect;
1897 eprint("!extra args %π\n", fp);
1900 if(issue(&r, a, &d) == -1){