2011-03-30 12:46:40 +00:00
|
|
|
/*
|
2011-07-10 12:14:23 +00:00
|
|
|
* aoe sd driver, copyright © 2007-9 coraid
|
2011-03-30 12:46:40 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
#include "io.h"
|
|
|
|
#include "../port/error.h"
|
|
|
|
#include "../port/sd.h"
|
|
|
|
#include "../port/netif.h"
|
|
|
|
#include "../port/aoe.h"
|
2011-07-10 12:14:23 +00:00
|
|
|
#include <fis.h>
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
extern char Echange[];
|
|
|
|
extern char Enotup[];
|
|
|
|
|
|
|
|
#define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
|
|
|
|
|
|
|
|
enum {
|
2011-07-10 12:14:23 +00:00
|
|
|
Maxpath = 128,
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
Probeintvl = 100, /* ms. between probes */
|
2011-07-10 12:14:23 +00:00
|
|
|
Probemax = 10*1000, /* max ms. to wait */
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct Ctlr Ctlr;
|
2011-07-10 12:14:23 +00:00
|
|
|
struct Ctlr {
|
2011-03-30 12:46:40 +00:00
|
|
|
QLock;
|
|
|
|
|
|
|
|
Ctlr *next;
|
|
|
|
SDunit *unit;
|
|
|
|
|
|
|
|
char path[Maxpath];
|
|
|
|
Chan *c;
|
|
|
|
|
|
|
|
ulong vers;
|
2011-07-10 12:14:23 +00:00
|
|
|
uchar drivechange;
|
|
|
|
Sfis;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
uvlong sectors;
|
|
|
|
char serial[20+1];
|
|
|
|
char firmware[8+1];
|
|
|
|
char model[40+1];
|
|
|
|
char ident[0x100];
|
|
|
|
};
|
|
|
|
|
|
|
|
static Lock ctlrlock;
|
|
|
|
static Ctlr *head;
|
|
|
|
static Ctlr *tail;
|
|
|
|
|
|
|
|
SDifc sdaoeifc;
|
|
|
|
|
|
|
|
static int
|
|
|
|
identify(Ctlr *c, ushort *id)
|
|
|
|
{
|
|
|
|
uchar oserial[21];
|
2011-07-10 12:14:23 +00:00
|
|
|
vlong osectors, s;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
osectors = c->sectors;
|
|
|
|
memmove(oserial, c->serial, sizeof c->serial);
|
2011-07-10 12:14:23 +00:00
|
|
|
s = idfeat(c, id);
|
|
|
|
if(s == -1){
|
|
|
|
uprint("%s: identify fails", c->unit->name);
|
|
|
|
print("%s\n", up->genbuf);
|
|
|
|
error(up->genbuf);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2011-07-10 12:14:23 +00:00
|
|
|
idmove(c->serial, id+10, 20);
|
|
|
|
idmove(c->firmware, id+23, 8);
|
|
|
|
idmove(c->model, id+27, 40);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
if((osectors == 0 || osectors != s) &&
|
|
|
|
memcmp(oserial, c->serial, sizeof oserial) != 0){
|
|
|
|
c->sectors = s;
|
2011-07-10 12:14:23 +00:00
|
|
|
c->drivechange = 1;
|
2011-03-30 12:46:40 +00:00
|
|
|
c->vers++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-07-10 12:14:23 +00:00
|
|
|
static void
|
|
|
|
aoectl(Ctlr *d, char *s)
|
|
|
|
{
|
|
|
|
Chan *c;
|
|
|
|
|
2015-07-23 20:05:46 +00:00
|
|
|
uprint("%s/ctl", d->path);
|
|
|
|
c = namec(up->genbuf, Aopen, OWRITE, 0);
|
2011-07-10 12:14:23 +00:00
|
|
|
if(waserror()){
|
|
|
|
print("sdaoectl: %s\n", up->errstr);
|
2015-07-23 20:05:46 +00:00
|
|
|
cclose(c);
|
2011-07-10 12:14:23 +00:00
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
devtab[c->type]->write(c, s, strlen(s), 0);
|
|
|
|
cclose(c);
|
2015-07-23 20:05:46 +00:00
|
|
|
poperror();
|
2011-07-10 12:14:23 +00:00
|
|
|
}
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
/* must call with d qlocked */
|
|
|
|
static int
|
|
|
|
aoeidentify(Ctlr *d, SDunit *u)
|
|
|
|
{
|
|
|
|
Chan *c;
|
|
|
|
|
2015-07-23 20:05:46 +00:00
|
|
|
uprint("%s/ident", d->path);
|
|
|
|
c = namec(up->genbuf, Aopen, OREAD, 0);
|
2011-03-30 12:46:40 +00:00
|
|
|
if(waserror()){
|
|
|
|
iprint("aoeidentify: %s\n", up->errstr);
|
2015-07-23 20:05:46 +00:00
|
|
|
cclose(c);
|
2011-03-30 12:46:40 +00:00
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
devtab[c->type]->read(c, d->ident, sizeof d->ident, 0);
|
|
|
|
cclose(c);
|
2015-07-23 20:05:46 +00:00
|
|
|
poperror();
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
d->feat = 0;
|
|
|
|
identify(d, (ushort*)d->ident);
|
|
|
|
|
|
|
|
memset(u->inquiry, 0, sizeof u->inquiry);
|
|
|
|
u->inquiry[2] = 2;
|
|
|
|
u->inquiry[3] = 2;
|
|
|
|
u->inquiry[4] = sizeof u->inquiry - 4;
|
|
|
|
memmove(u->inquiry+8, d->model, 40);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Ctlr*
|
|
|
|
ctlrlookup(char *path)
|
|
|
|
{
|
|
|
|
Ctlr *c;
|
|
|
|
|
|
|
|
lock(&ctlrlock);
|
2015-07-23 20:05:46 +00:00
|
|
|
for(c = head; c != nil; c = c->next)
|
2011-03-30 12:46:40 +00:00
|
|
|
if(strcmp(c->path, path) == 0)
|
|
|
|
break;
|
|
|
|
unlock(&ctlrlock);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Ctlr*
|
|
|
|
newctlr(char *path)
|
|
|
|
{
|
|
|
|
Ctlr *c;
|
|
|
|
|
|
|
|
if(ctlrlookup(path))
|
|
|
|
error(Eexist);
|
|
|
|
|
|
|
|
if((c = malloc(sizeof *c)) == nil)
|
|
|
|
return 0;
|
|
|
|
kstrcpy(c->path, path, sizeof c->path);
|
|
|
|
lock(&ctlrlock);
|
|
|
|
if(head != nil)
|
|
|
|
tail->next = c;
|
|
|
|
else
|
|
|
|
head = c;
|
|
|
|
tail = c;
|
|
|
|
unlock(&ctlrlock);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
delctlr(Ctlr *c)
|
|
|
|
{
|
|
|
|
Ctlr *x, *prev;
|
|
|
|
|
|
|
|
lock(&ctlrlock);
|
|
|
|
|
2015-07-23 20:05:46 +00:00
|
|
|
for(prev = 0, x = head; x != nil; prev = x, x = c->next)
|
2011-03-30 12:46:40 +00:00
|
|
|
if(strcmp(c->path, x->path) == 0)
|
|
|
|
break;
|
2015-07-23 20:05:46 +00:00
|
|
|
if(x == nil){
|
2011-03-30 12:46:40 +00:00
|
|
|
unlock(&ctlrlock);
|
|
|
|
error(Enonexist);
|
|
|
|
}
|
|
|
|
|
2015-07-23 20:05:46 +00:00
|
|
|
if(prev != nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
prev->next = x->next;
|
|
|
|
else
|
|
|
|
head = x->next;
|
|
|
|
if(x->next == nil)
|
|
|
|
tail = prev;
|
|
|
|
unlock(&ctlrlock);
|
|
|
|
|
2015-07-23 20:05:46 +00:00
|
|
|
if(x->c != nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
cclose(x->c);
|
|
|
|
free(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
static SDev*
|
|
|
|
aoeprobe(char *path, SDev *s)
|
|
|
|
{
|
|
|
|
int n, i;
|
|
|
|
char *p;
|
|
|
|
Chan *c;
|
|
|
|
Ctlr *ctlr;
|
|
|
|
|
2015-07-23 20:05:46 +00:00
|
|
|
if((p = strrchr(path, '/')) == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Ebadarg);
|
|
|
|
*p = 0;
|
|
|
|
uprint("%s/ctl", path);
|
|
|
|
*p = '/';
|
|
|
|
c = namec(up->genbuf, Aopen, OWRITE, 0);
|
|
|
|
if(waserror()) {
|
|
|
|
cclose(c);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
n = uprint("discover %s", p+1);
|
|
|
|
devtab[c->type]->write(c, up->genbuf, n, 0);
|
|
|
|
cclose(c);
|
2015-07-23 20:05:46 +00:00
|
|
|
poperror();
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-07-10 12:14:23 +00:00
|
|
|
for(i = 0;; i += Probeintvl){
|
|
|
|
if(i > Probemax || waserror())
|
|
|
|
error(Etimedout);
|
2011-03-30 12:46:40 +00:00
|
|
|
tsleep(&up->sleep, return0, 0, Probeintvl);
|
2011-07-10 12:14:23 +00:00
|
|
|
poperror();
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
uprint("%s/ident", path);
|
2011-07-10 12:14:23 +00:00
|
|
|
if(waserror())
|
|
|
|
continue;
|
|
|
|
c = namec(up->genbuf, Aopen, OREAD, 0);
|
|
|
|
poperror();
|
|
|
|
cclose(c);
|
|
|
|
|
|
|
|
ctlr = newctlr(path);
|
|
|
|
break;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2011-07-10 12:14:23 +00:00
|
|
|
|
|
|
|
if(s == nil && (s = malloc(sizeof *s)) == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
return nil;
|
|
|
|
s->ctlr = ctlr;
|
|
|
|
s->ifc = &sdaoeifc;
|
|
|
|
s->nunit = 1;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *probef[32];
|
2011-07-10 12:14:23 +00:00
|
|
|
static char *probebuf;
|
2011-03-30 12:46:40 +00:00
|
|
|
static int nprobe;
|
|
|
|
|
|
|
|
static SDev*
|
|
|
|
aoepnp(void)
|
|
|
|
{
|
|
|
|
int i, id;
|
|
|
|
char *p;
|
|
|
|
SDev *h, *t, *s;
|
|
|
|
|
2015-07-23 20:05:46 +00:00
|
|
|
if((p = getconf("aoedev")) == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
return 0;
|
2011-07-10 12:14:23 +00:00
|
|
|
kstrdup(&probebuf, p);
|
|
|
|
nprobe = tokenize(probebuf, probef, nelem(probef));
|
2011-03-30 12:46:40 +00:00
|
|
|
h = t = 0;
|
|
|
|
for(i = 0; i < nprobe; i++){
|
2014-12-19 01:37:40 +00:00
|
|
|
p = probef[i];
|
|
|
|
if(strlen(p) < 2)
|
2011-03-30 12:46:40 +00:00
|
|
|
continue;
|
2014-12-19 01:37:40 +00:00
|
|
|
id = 'e';
|
|
|
|
if(p[1] == '!'){
|
|
|
|
id = p[0];
|
|
|
|
p += 2;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* shorthand for: id!lun -> id!#æ/aoe/lun
|
|
|
|
* because we cannot type æ in the bootloader console.
|
|
|
|
*/
|
|
|
|
if(strchr(p, '/') == nil){
|
|
|
|
char tmp[64];
|
|
|
|
|
|
|
|
snprint(tmp, sizeof(tmp), "%c!#æ/aoe/%s", (char)id, p);
|
|
|
|
|
|
|
|
probef[i] = nil;
|
|
|
|
kstrdup(&probef[i], tmp);
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
s = malloc(sizeof *s);
|
|
|
|
if(s == nil)
|
|
|
|
break;
|
|
|
|
s->ctlr = 0;
|
|
|
|
s->idno = id;
|
|
|
|
s->ifc = &sdaoeifc;
|
|
|
|
s->nunit = 1;
|
|
|
|
|
|
|
|
if(h)
|
|
|
|
t->next = s;
|
|
|
|
else
|
|
|
|
h = s;
|
|
|
|
t = s;
|
|
|
|
}
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Ctlr*
|
|
|
|
pnpprobe(SDev *sd)
|
|
|
|
{
|
2011-07-10 12:14:23 +00:00
|
|
|
int j;
|
2011-03-30 12:46:40 +00:00
|
|
|
char *p;
|
|
|
|
static int i;
|
|
|
|
|
|
|
|
if(i > nprobe)
|
|
|
|
return 0;
|
|
|
|
p = probef[i++];
|
|
|
|
if(strlen(p) < 2)
|
|
|
|
return 0;
|
|
|
|
if(p[1] == '!')
|
|
|
|
p += 2;
|
|
|
|
|
2011-07-10 12:14:23 +00:00
|
|
|
for(j = 0;; j += Probeintvl){
|
|
|
|
if(j > Probemax){
|
|
|
|
print("#æ: pnpprobe: %s: %s\n", probef[i-1], up->errstr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(waserror()){
|
|
|
|
tsleep(&up->sleep, return0, 0, Probeintvl);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
sd = aoeprobe(p, sd);
|
|
|
|
poperror();
|
|
|
|
break;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2011-07-10 12:14:23 +00:00
|
|
|
print("#æ: pnpprobe establishes %s in %dms\n", probef[i-1], j);
|
|
|
|
aoectl(sd->ctlr, "nofail on");
|
2011-03-30 12:46:40 +00:00
|
|
|
return sd->ctlr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
aoeverify(SDunit *u)
|
|
|
|
{
|
|
|
|
SDev *s;
|
|
|
|
Ctlr *c;
|
|
|
|
|
|
|
|
s = u->dev;
|
|
|
|
c = s->ctlr;
|
|
|
|
if(c == nil && (s->ctlr = c = pnpprobe(s)) == nil)
|
|
|
|
return 0;
|
2011-07-10 12:14:23 +00:00
|
|
|
c->drivechange = 1;
|
2011-03-30 12:46:40 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
aoeconnect(SDunit *u, Ctlr *c)
|
|
|
|
{
|
|
|
|
qlock(c);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(c);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
aoeidentify(u->dev->ctlr, u);
|
|
|
|
if(c->c)
|
|
|
|
cclose(c->c);
|
|
|
|
c->c = 0;
|
|
|
|
uprint("%s/data", c->path);
|
|
|
|
c->c = namec(up->genbuf, Aopen, ORDWR, 0);
|
|
|
|
qunlock(c);
|
|
|
|
poperror();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
aoeonline(SDunit *u)
|
|
|
|
{
|
|
|
|
Ctlr *c;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
c = u->dev->ctlr;
|
|
|
|
r = 0;
|
|
|
|
|
2011-07-10 12:14:23 +00:00
|
|
|
if((c->feat&Datapi) && c->drivechange){
|
2011-03-30 12:46:40 +00:00
|
|
|
if(aoeconnect(u, c) == 0 && (r = scsionline(u)) > 0)
|
2011-07-10 12:14:23 +00:00
|
|
|
c->drivechange = 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2011-07-10 12:14:23 +00:00
|
|
|
if(c->drivechange){
|
2011-03-30 12:46:40 +00:00
|
|
|
if(aoeconnect(u, c) == -1)
|
|
|
|
return 0;
|
|
|
|
r = 2;
|
2011-07-10 12:14:23 +00:00
|
|
|
c->drivechange = 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
u->sectors = c->sectors;
|
|
|
|
u->secsize = Aoesectsz;
|
|
|
|
} else
|
|
|
|
r = 1;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2011-07-10 12:14:23 +00:00
|
|
|
static long
|
|
|
|
aoebio(SDunit *u, int, int write, void *a, long count, uvlong lba)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-07-10 12:14:23 +00:00
|
|
|
uchar *data;
|
|
|
|
int n;
|
2011-03-30 12:46:40 +00:00
|
|
|
long (*rio)(Chan*, void*, long, vlong);
|
|
|
|
Ctlr *c;
|
|
|
|
|
2011-07-10 12:14:23 +00:00
|
|
|
c = u->dev->ctlr;
|
2011-03-30 12:46:40 +00:00
|
|
|
// if(c->feat & Datapi)
|
2011-07-10 12:14:23 +00:00
|
|
|
// return scsibio(u, lun, write, a, count, lba);
|
|
|
|
data = a;
|
|
|
|
if(write)
|
2011-03-30 12:46:40 +00:00
|
|
|
rio = devtab[c->c->type]->write;
|
2011-07-10 12:14:23 +00:00
|
|
|
else
|
|
|
|
rio = devtab[c->c->type]->read;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
if(waserror()){
|
|
|
|
if(strcmp(up->errstr, Echange) == 0 ||
|
|
|
|
strcmp(up->errstr, Enotup) == 0)
|
2011-07-10 12:14:23 +00:00
|
|
|
u->sectors = 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
nexterror();
|
|
|
|
}
|
2011-07-10 12:14:23 +00:00
|
|
|
n = rio(c->c, data, Aoesectsz * count, Aoesectsz * lba);
|
2011-03-30 12:46:40 +00:00
|
|
|
poperror();
|
2011-07-10 12:14:23 +00:00
|
|
|
return n;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2011-07-10 12:14:23 +00:00
|
|
|
static int
|
|
|
|
flushcache(Ctlr *)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-07-10 12:14:23 +00:00
|
|
|
static int
|
|
|
|
aoerio(SDreq *r)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-07-10 12:14:23 +00:00
|
|
|
int i, count, rw;
|
|
|
|
uvlong lba;
|
|
|
|
Ctlr *c;
|
|
|
|
SDunit *u;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-07-10 12:14:23 +00:00
|
|
|
u = r->unit;
|
|
|
|
c = u->dev->ctlr;
|
|
|
|
// if(c->feat & Datapi)
|
|
|
|
// return aoeriopkt(r, d);
|
|
|
|
|
|
|
|
if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
|
|
|
|
qlock(c);
|
|
|
|
i = flushcache(c);
|
|
|
|
qunlock(c);
|
|
|
|
if(i == 0)
|
|
|
|
return sdsetsense(r, SDok, 0, 0, 0);
|
|
|
|
return sdsetsense(r, SDcheck, 3, 0xc, 2);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2011-07-10 12:14:23 +00:00
|
|
|
|
|
|
|
if((i = sdfakescsi(r)) != SDnostatus){
|
|
|
|
r->status = i;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
|
|
|
|
return i;
|
|
|
|
r->rlen = aoebio(u, r->lun, rw == SDwrite, r->data, count, lba);
|
|
|
|
return r->status = SDok;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
aoerctl(SDunit *u, char *p, int l)
|
|
|
|
{
|
|
|
|
Ctlr *c;
|
|
|
|
char *e, *op;
|
|
|
|
|
|
|
|
if((c = u->dev->ctlr) == nil)
|
|
|
|
return 0;
|
|
|
|
e = p+l;
|
|
|
|
op = p;
|
|
|
|
|
|
|
|
p = seprint(p, e, "model\t%s\n", c->model);
|
|
|
|
p = seprint(p, e, "serial\t%s\n", c->serial);
|
|
|
|
p = seprint(p, e, "firm %s\n", c->firmware);
|
|
|
|
p = seprint(p, e, "flag ");
|
2011-07-10 12:14:23 +00:00
|
|
|
p = pflag(p, e, c);
|
2011-03-30 12:46:40 +00:00
|
|
|
p = seprint(p, e, "geometry %llud %d\n", c->sectors, Aoesectsz);
|
|
|
|
return p-op;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
aoewctl(SDunit *, Cmdbuf *cmd)
|
|
|
|
{
|
|
|
|
cmderror(cmd, Ebadarg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SDev*
|
|
|
|
aoeprobew(DevConf *c)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
p = strchr(c->type, '/');
|
|
|
|
if(p == nil || strlen(p) > Maxpath - 11)
|
|
|
|
error(Ebadarg);
|
|
|
|
if(p[1] == '#')
|
|
|
|
p++; /* hack */
|
|
|
|
if(ctlrlookup(p))
|
|
|
|
error(Einuse);
|
|
|
|
return aoeprobe(p, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
aoeclear(SDev *s)
|
|
|
|
{
|
|
|
|
delctlr((Ctlr *)s->ctlr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
|
|
|
aoertopctl(SDev *s, char *p, char *e)
|
|
|
|
{
|
|
|
|
Ctlr *c;
|
|
|
|
|
|
|
|
c = s->ctlr;
|
2011-07-10 12:14:23 +00:00
|
|
|
return seprint(p, e, "%s aoe %s\n", s->name, c? c->path: "");
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
aoewtopctl(SDev *, Cmdbuf *cmd)
|
|
|
|
{
|
|
|
|
switch(cmd->nf){
|
|
|
|
default:
|
|
|
|
cmderror(cmd, Ebadarg);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDifc sdaoeifc = {
|
|
|
|
"aoe",
|
|
|
|
|
|
|
|
aoepnp,
|
|
|
|
nil, /* legacy */
|
|
|
|
nil, /* enable */
|
|
|
|
nil, /* disable */
|
|
|
|
|
|
|
|
aoeverify,
|
|
|
|
aoeonline,
|
|
|
|
aoerio,
|
|
|
|
aoerctl,
|
|
|
|
aoewctl,
|
|
|
|
|
2011-07-10 12:14:23 +00:00
|
|
|
aoebio,
|
2011-03-30 12:46:40 +00:00
|
|
|
aoeprobew, /* probe */
|
|
|
|
aoeclear, /* clear */
|
|
|
|
aoertopctl,
|
|
|
|
aoewtopctl,
|
|
|
|
};
|