]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/disk/smart/ata.c
Add Erik Quanstrom's smart tool for ATA SMART.
[plan9front.git] / sys / src / cmd / disk / smart / ata.c
1 #include <u.h>
2 #include <libc.h>
3 #include <fis.h>
4 #include "smart.h"
5
6 enum{
7         Nop,
8         Idall,
9         Idpkt,
10         Smart,
11         Id,
12         Sig,
13
14         Cmdsz   = 18,
15         Replysz = 18,
16
17 };
18
19 typedef struct Atatab Atatab;
20 struct Atatab {
21         ushort  cc;
22         uchar   protocol;
23         char    *name;
24 };
25
26 Atatab atatab[] = {
27 [Nop]   0x00,   Pnd|P28,        "nop",
28 [Idall] 0xff,   Pin|Ppio|P28,   "identify * device",
29 [Idpkt] 0xa1,   Pin|Ppio|P28,   "identify packet device",
30 [Smart] 0xb0,   Pnd|P28,        "smart",
31 [Id]    0xec,   Pin|Ppio|P28,   "identify device",
32 [Sig]   0xf000, Pnd|P28,        "signature",
33 };
34
35 typedef struct Rcmd Rcmd;
36 struct Rcmd{
37         uchar   sdcmd;          /* sd command; 0xff means ata passthrough */
38         uchar   ataproto;       /* ata protocol.  non-data, pio, reset, dd, etc. */
39         uchar   fis[Fissize];
40 };
41
42 typedef struct Req Req;
43 struct Req {
44         char    haverfis;
45         Rcmd    cmd;
46         Rcmd    reply;
47         uchar   data[0x200];
48         uint    count;
49 };
50
51 static int
52 issueata(Req *r, Sdisk *d, int errok)
53 {
54         char buf[ERRMAX];
55         int ok, rv;
56
57         if((rv = write(d->fd, &r->cmd, Cmdsz)) != Cmdsz){
58                 /* handle non-atazz compatable kernels */
59                 rerrstr(buf, sizeof buf);
60                 if(rv != -1 || strstr(buf, "bad arg in system call") != 0)
61                         eprint(d, "fis write error: %r\n");
62                 return -1;
63         }
64
65         werrstr("");
66         switch(r->cmd.ataproto & Pdatam){
67         default:
68                 ok = read(d->fd, "", 0) == 0;
69                 break;
70         case Pin:
71                 ok = read(d->fd, r->data, r->count) == r->count;
72                 break;
73         case Pout:
74                 ok = write(d->fd, r->data, r->count) == r->count;
75                 break;
76         }
77         rv = 0;
78         if(ok == 0){
79                 rerrstr(buf, sizeof buf);
80                 if(!errok && strstr(buf, "not sata") == 0)
81                         eprint(d, "xfer error: %.2ux%.2ux: %r\n", r->cmd.fis[0], r->cmd.fis[2]);
82                 rv = -1;
83         }
84         if(read(d->fd, &r->reply, Replysz) != Replysz){
85                 if(!errok)
86                         eprint(d, "status fis read error: %r\n");
87                 return -1;
88         }
89         r->haverfis = 1;
90         return rv;
91 }
92
93 int
94 issueatat(Req *r, int i, Sdisk *d, int e)
95 {
96         uchar *fis;
97         Atatab *a;
98
99         a = atatab + i;
100         r->haverfis = 0;
101         r->cmd.sdcmd = 0xff;
102         r->cmd.ataproto = a->protocol;
103         fis = r->cmd.fis;
104         fis[0] = H2dev;
105         if(a->cc & 0xff00)
106                 fis[0] = a->cc >> 8;
107         fis[1] = Fiscmd;
108         if(a->cc != 0xff)
109                 fis[2] = a->cc;
110         return issueata(r, d, e);
111 }
112
113 int
114 ataprobe(Sdisk *d)
115 {
116         int rv;
117         Req r;
118
119         memset(&r, 0, sizeof r);
120         if(issueatat(&r, Sig, d, 1) == -1)
121                 return -1;
122         setfissig(d, fistosig(r.reply.fis));
123         memset(&r, 0, sizeof r);
124         r.count = 0x200;
125         identifyfis(d, r.cmd.fis);
126         if((rv = issueatat(&r, Idall, d, 1)) != -1){
127                 idfeat(d, (ushort*)r.data);
128                 if((d->feat & Dsmart) == 0)
129                         rv = -1;
130         }
131         return rv;
132 }
133
134 int
135 smartfis(Sfis *f, uchar *c, int n)
136 {
137         if((f->feat & Dsmart) == 0)
138                 return -1;
139         skelfis(c);
140         c[2] = 0xb0;
141         c[3] = 0xd8 + n;        /* able smart */
142         c[5] = 0x4f;
143         c[6] = 0xc2;
144         return 0;
145 }
146
147 int
148 ataenable(Sdisk *d)
149 {
150         int rv;
151         Req r;
152
153         memset(&r, 0, sizeof r);
154         smartfis(d, r.cmd.fis, 0);
155         rv = issueatat(&r, Smart, d, 0);
156         return rv;
157 }
158
159 void
160 smartrsfis(Sfis*, uchar *c)
161 {
162         skelfis(c);
163         c[2] = 0xb0;
164         c[3] = 0xda;            /* return smart status */
165         c[5] = 0x4f;
166         c[6] = 0xc2;
167 }
168
169 int
170 atastatus(Sdisk *d, char *s, int l)
171 {
172         uchar *fis;
173         int rv;
174         Req r;
175
176         memset(&r, 0, sizeof r);
177         smartrsfis(d, r.cmd.fis);
178         rv = issueatat(&r, Smart, d, 0);
179         *s = 0;
180         if(rv != -1){
181                 fis = r.reply.fis;
182                 if(fis[5] == 0x4f &&
183                    fis[6] == 0xc2)
184                         snprint(s, l, "normal");
185                 else{
186                         snprint(s, l, "threshold exceeded");
187                         rv = -1;
188                 }
189         } else
190                 snprint(s, l, "smart error");
191         return rv;
192 }