192 lines · 3.2 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <fis.h>#include "smart.h" enum{	Nop,	Idall,	Idpkt,	Smart,	Id,	Sig, 	Cmdsz	= 18,	Replysz	= 18, }; typedef struct Atatab Atatab;struct Atatab {	ushort	cc;	uchar	protocol;	char	*name;}; Atatab atatab[] = {[Nop]	0x00,	Pnd|P28,	"nop",[Idall]	0xff,	Pin|Ppio|P28,	"identify * device",[Idpkt]	0xa1,	Pin|Ppio|P28,	"identify packet device",[Smart]	0xb0,	Pnd|P28,	"smart",[Id]	0xec,	Pin|Ppio|P28,	"identify device",[Sig]	0xf000,	Pnd|P28,	"signature",}; typedef struct Rcmd Rcmd;struct Rcmd{	uchar	sdcmd;		/* sd command; 0xff means ata passthrough */	uchar	ataproto;	/* ata protocol.  non-data, pio, reset, dd, etc. */	uchar	fis[Fissize];}; typedef struct Req Req;struct Req {	char	haverfis;	Rcmd	cmd;	Rcmd	reply;	uchar	data[0x200];	uint	count;}; static intissueata(Req *r, Sdisk *d, int errok){	char buf[ERRMAX];	int ok, rv; 	if((rv = write(d->fd, &r->cmd, Cmdsz)) != Cmdsz){		/* handle non-atazz compatable kernels */		rerrstr(buf, sizeof buf);		if(rv != -1 || strstr(buf, "bad arg in system call") != 0)			eprint(d, "fis write error: %r\n");		return -1;	} 	werrstr("");	switch(r->cmd.ataproto & Pdatam){	default:		ok = read(d->fd, "", 0) == 0;		break;	case Pin:		ok = read(d->fd, r->data, r->count) == r->count;		break;	case Pout:		ok = write(d->fd, r->data, r->count) == r->count;		break;	}	rv = 0;	if(ok == 0){		rerrstr(buf, sizeof buf);		if(!errok && strstr(buf, "not sata") == 0)			eprint(d, "xfer error: %.2ux%.2ux: %r\n", r->cmd.fis[0], r->cmd.fis[2]);		rv = -1;	}	if(read(d->fd, &r->reply, Replysz) != Replysz){		if(!errok)			eprint(d, "status fis read error: %r\n");		return -1;	}	r->haverfis = 1;	return rv;} intissueatat(Req *r, int i, Sdisk *d, int e){	uchar *fis;	Atatab *a; 	a = atatab + i;	r->haverfis = 0;	r->cmd.sdcmd = 0xff;	r->cmd.ataproto = a->protocol;	fis = r->cmd.fis;	fis[0] = H2dev;	if(a->cc & 0xff00)		fis[0] = a->cc >> 8;	fis[1] = Fiscmd;	if(a->cc != 0xff)		fis[2] = a->cc;	return issueata(r, d, e);} intataprobe(Sdisk *d){	int rv;	Req r; 	memset(&r, 0, sizeof r);	if(issueatat(&r, Sig, d, 1) == -1)		return -1;	setfissig(d, fistosig(r.reply.fis));	memset(&r, 0, sizeof r);	r.count = 0x200;	identifyfis(d, r.cmd.fis);	if((rv = issueatat(&r, Idall, d, 1)) != -1){		idfeat(d, (ushort*)r.data);		if((d->feat & Dsmart) == 0)			rv = -1;	}	return rv;} intsmartfis(Sfis *f, uchar *c, int n){	if((f->feat & Dsmart) == 0)		return -1;	skelfis(c);	c[2] = 0xb0;	c[3] = 0xd8 + n;	/* able smart */	c[5] = 0x4f;	c[6] = 0xc2;	return 0;} intataenable(Sdisk *d){	int rv;	Req r; 	memset(&r, 0, sizeof r);	smartfis(d, r.cmd.fis, 0);	rv = issueatat(&r, Smart, d, 0);	return rv;} voidsmartrsfis(Sfis*, uchar *c){	skelfis(c);	c[2] = 0xb0;	c[3] = 0xda;		/* return smart status */	c[5] = 0x4f;	c[6] = 0xc2;} intatastatus(Sdisk *d, char *s, int l){	uchar *fis;	int rv;	Req r; 	memset(&r, 0, sizeof r);	smartrsfis(d, r.cmd.fis);	rv = issueatat(&r, Smart, d, 0);	*s = 0;	if(rv != -1){		fis = r.reply.fis;		if(fis[5] == 0x4f &&		   fis[6] == 0xc2)			snprint(s, l, "normal");		else{			snprint(s, l, "threshold exceeded");			rv = -1;		}	} else		snprint(s, l, "smart error");	return rv;}