101a344a2SDavid du Colombier /*
201a344a2SDavid du Colombier * drive HP optical-disc jukeboxes (e.g. HP 1200EX).
301a344a2SDavid du Colombier * used to issue SCSI commands directly to the host adapter;
401a344a2SDavid du Colombier * now (via scsi.c) it issues them via scsi(2) using
501a344a2SDavid du Colombier * /dev/sdXX/raw to run the robotics, and uses normal i/o
601a344a2SDavid du Colombier * on /dev/sdXX/data to run the drives.
701a344a2SDavid du Colombier */
801a344a2SDavid du Colombier #include "all.h"
901a344a2SDavid du Colombier #include "io.h"
1001a344a2SDavid du Colombier
1101a344a2SDavid du Colombier enum {
1201a344a2SDavid du Colombier SCSInone = SCSIread,
1301a344a2SDavid du Colombier MAXDRIVE = 10,
1401a344a2SDavid du Colombier MAXSIDE = 500, /* max. disc sides */
1501a344a2SDavid du Colombier
1601a344a2SDavid du Colombier TWORM = MINUTE(10),
1701a344a2SDavid du Colombier THYSTER = SECOND(10),
1801a344a2SDavid du Colombier
1901a344a2SDavid du Colombier Sectorsz = 512, /* usual disk sector size */
2001a344a2SDavid du Colombier
2101a344a2SDavid du Colombier Jukemagic = 0xbabfece2,
2201a344a2SDavid du Colombier };
2301a344a2SDavid du Colombier
2401a344a2SDavid du Colombier typedef struct Side Side;
2501a344a2SDavid du Colombier struct Side
2601a344a2SDavid du Colombier {
2701a344a2SDavid du Colombier QLock; /* protects loading/unloading */
2801a344a2SDavid du Colombier int elem; /* element number */
2901a344a2SDavid du Colombier int drive; /* if loaded, where */
3001a344a2SDavid du Colombier uchar status; /* Sunload, etc */
3101a344a2SDavid du Colombier uchar rot; /* if backside */
3201a344a2SDavid du Colombier int ord; /* ordinal number for labeling */
3301a344a2SDavid du Colombier
3401a344a2SDavid du Colombier Timet time; /* time since last access, to unspin */
3501a344a2SDavid du Colombier Timet stime; /* time since last spinup, for hysteresis */
3601a344a2SDavid du Colombier long nblock; /* number of native blocks */
3701a344a2SDavid du Colombier long block; /* bytes per native block */
3801a344a2SDavid du Colombier long mult; /* multiplier to get plan9 blocks */
3901a344a2SDavid du Colombier long max; /* max size in plan9 blocks */
4001a344a2SDavid du Colombier };
4101a344a2SDavid du Colombier
4201a344a2SDavid du Colombier typedef struct Juke Juke;
4301a344a2SDavid du Colombier struct Juke
4401a344a2SDavid du Colombier {
4501a344a2SDavid du Colombier QLock; /* protects drive mechanism */
4601a344a2SDavid du Colombier Side side[MAXSIDE];
4701a344a2SDavid du Colombier int nside; /* # of storage elements (*2 if rev) */
4801a344a2SDavid du Colombier int ndrive; /* # of transfer elements */
4901a344a2SDavid du Colombier Device* juke; /* devworm of changer */
5001a344a2SDavid du Colombier Device* drive[MAXDRIVE]; /* devworm for i/o */
5101a344a2SDavid du Colombier uchar offline[MAXDRIVE]; /* drives removed from service */
5201a344a2SDavid du Colombier int isfixedsize; /* flag: one size fits all? */
5301a344a2SDavid du Colombier long fixedsize; /* the one size that fits all */
5401a344a2SDavid du Colombier int probeok; /* wait for init to probe */
5501a344a2SDavid du Colombier
5601a344a2SDavid du Colombier Scsi* robot; /* scsi(2) interface to robotics */
5701a344a2SDavid du Colombier char* robotdir; /* /dev/sdXX name */
5801a344a2SDavid du Colombier
5901a344a2SDavid du Colombier /*
6001a344a2SDavid du Colombier * geometry returned by mode sense.
6101a344a2SDavid du Colombier * a *0 number (such as mt0) is the `element number' of the
6201a344a2SDavid du Colombier * first element of that type (e.g., mt, or motor transport).
6301a344a2SDavid du Colombier * an n* number is the quantity of them.
6401a344a2SDavid du Colombier */
6501a344a2SDavid du Colombier int mt0, nmt; /* motor transports (robot pickers) */
6601a344a2SDavid du Colombier int se0, nse; /* storage elements (discs, slots) */
6701a344a2SDavid du Colombier int ie0, nie; /* interchange elements (mailbox slots) */
6801a344a2SDavid du Colombier int dt0, ndt; /* drives (data transfer?) */
6901a344a2SDavid du Colombier int rot; /* if true, discs are double-sided */
7001a344a2SDavid du Colombier
7101a344a2SDavid du Colombier ulong magic;
7201a344a2SDavid du Colombier Juke* link;
7301a344a2SDavid du Colombier };
7401a344a2SDavid du Colombier static Juke* jukelist;
7501a344a2SDavid du Colombier
7601a344a2SDavid du Colombier enum
7701a344a2SDavid du Colombier {
7801a344a2SDavid du Colombier Sempty = 0, /* does not exist */
7901a344a2SDavid du Colombier Sunload, /* on the shelf */
8001a344a2SDavid du Colombier Sstart, /* loaded and spinning */
8101a344a2SDavid du Colombier };
8201a344a2SDavid du Colombier
8301a344a2SDavid du Colombier static int bestdrive(Juke*, int);
8401a344a2SDavid du Colombier static void element(Juke*, int);
8501a344a2SDavid du Colombier static int mmove(Juke*, int, int, int, int);
8601a344a2SDavid du Colombier static void shelves(void);
8701a344a2SDavid du Colombier static int waitready(Juke *, Device*);
8801a344a2SDavid du Colombier static int wormsense(Device*);
8901a344a2SDavid du Colombier static Side* wormunit(Device*);
9001a344a2SDavid du Colombier
9101a344a2SDavid du Colombier /* create a new label and try to write it */
9201a344a2SDavid du Colombier static void
newlabel(Device * d,Off labelblk,char * labelbuf,unsigned vord)9301a344a2SDavid du Colombier newlabel(Device *d, Off labelblk, char *labelbuf, unsigned vord)
9401a344a2SDavid du Colombier {
9501a344a2SDavid du Colombier Label *label = (Label *)labelbuf;
9601a344a2SDavid du Colombier
9701a344a2SDavid du Colombier memset(labelbuf, 0, RBUFSIZE);
9801a344a2SDavid du Colombier label->magic = Labmagic;
9901a344a2SDavid du Colombier label->ord = vord;
10001a344a2SDavid du Colombier strncpy(label->service, service, sizeof label->service);
10101a344a2SDavid du Colombier
1026d1e5220SDavid du Colombier if (!okay("write new label"))
1036d1e5220SDavid du Colombier print("NOT writing new label\n");
1046d1e5220SDavid du Colombier else if (wormwrite(d, labelblk, labelbuf))
10501a344a2SDavid du Colombier /* wormwrite will have complained in detail */
10601a344a2SDavid du Colombier print("can't write new label on side %d\n", vord);
10701a344a2SDavid du Colombier else
10801a344a2SDavid du Colombier print("wrote new label on side %d\n", vord);
10901a344a2SDavid du Colombier }
11001a344a2SDavid du Colombier
11101a344a2SDavid du Colombier /* check for label in last block. call with v qlocked. */
11201a344a2SDavid du Colombier Side*
wormlabel(Device * d,Side * v)11301a344a2SDavid du Colombier wormlabel(Device *d, Side *v)
11401a344a2SDavid du Colombier {
11501a344a2SDavid du Colombier int vord;
11601a344a2SDavid du Colombier Off labelblk = v->max - 1; /* last block */
11701a344a2SDavid du Colombier char labelbuf[RBUFSIZE];
11801a344a2SDavid du Colombier Label *label = (Label *)labelbuf;
11901a344a2SDavid du Colombier Juke *w = d->private;
12001a344a2SDavid du Colombier
12101a344a2SDavid du Colombier /* wormread calls wormunit, which locks v */
12201a344a2SDavid du Colombier vord = v->ord;
12301a344a2SDavid du Colombier qunlock(v);
12401a344a2SDavid du Colombier
12501a344a2SDavid du Colombier memset(label, 0, sizeof *label);
12601a344a2SDavid du Colombier if (wormread(d, labelblk, labelbuf)) {
12701a344a2SDavid du Colombier /*
12801a344a2SDavid du Colombier * wormread will have complained in detail about the error;
12901a344a2SDavid du Colombier * no need to repeat most of that detail.
13001a344a2SDavid du Colombier * probably an unwritten WORM-disc label; write a new one.
13101a344a2SDavid du Colombier */
13201a344a2SDavid du Colombier print("error reading label block of side %d\n", vord);
13301a344a2SDavid du Colombier newlabel(d, labelblk, labelbuf, vord);
13401a344a2SDavid du Colombier } else if (label->magic != Labmagic) {
13501a344a2SDavid du Colombier swab8(&label->magic);
13601a344a2SDavid du Colombier if (label->magic == Labmagic) {
13701a344a2SDavid du Colombier print(
13801a344a2SDavid du Colombier "side %d's label magic byte-swapped; filsys should be configured with xD",
13901a344a2SDavid du Colombier vord);
14001a344a2SDavid du Colombier swab2(&label->ord);
14101a344a2SDavid du Colombier /* could look for Devswab in Juke's filsys */
14201a344a2SDavid du Colombier } else {
14301a344a2SDavid du Colombier /*
14401a344a2SDavid du Colombier * magic # is wrong in both byte orders, thus
14501a344a2SDavid du Colombier * probably the label is empty on RW media,
14601a344a2SDavid du Colombier * so create a new one and try to write it.
14701a344a2SDavid du Colombier */
14801a344a2SDavid du Colombier print("bad magic number in label of side %d\n", vord);
14901a344a2SDavid du Colombier newlabel(d, labelblk, labelbuf, vord);
15001a344a2SDavid du Colombier }
15101a344a2SDavid du Colombier }
15201a344a2SDavid du Colombier
15301a344a2SDavid du Colombier qlock(v);
15401a344a2SDavid du Colombier if (v->ord != vord)
15501a344a2SDavid du Colombier panic("wormlabel: side %d switched ordinal to %d underfoot",
15601a344a2SDavid du Colombier vord, v->ord);
15701a344a2SDavid du Colombier if (label->ord != vord) {
15801a344a2SDavid du Colombier print(
15901a344a2SDavid du Colombier "labelled worm side %Z has wrong ordinal in label (%d, want %d)",
16001a344a2SDavid du Colombier d, label->ord, vord);
16101a344a2SDavid du Colombier qunlock(v);
16201a344a2SDavid du Colombier cmd_wormreset(0, nil); /* put discs away */
16301a344a2SDavid du Colombier panic("wrong ordinal in label");
16401a344a2SDavid du Colombier }
16501a344a2SDavid du Colombier
16601a344a2SDavid du Colombier print("label %Z ordinal %d\n", d, v->ord);
16701a344a2SDavid du Colombier qunlock(v);
16801a344a2SDavid du Colombier /*
16901a344a2SDavid du Colombier * wormunit should return without calling us again,
17001a344a2SDavid du Colombier * since v is now known.
17101a344a2SDavid du Colombier */
17201a344a2SDavid du Colombier if (w != d->private)
17301a344a2SDavid du Colombier panic("wormlabel: w != %Z->private", d);
17401a344a2SDavid du Colombier return wormunit(d);
17501a344a2SDavid du Colombier }
17601a344a2SDavid du Colombier
17701a344a2SDavid du Colombier /*
17801a344a2SDavid du Colombier * mounts and spins up the device
17901a344a2SDavid du Colombier * locks the structure
18001a344a2SDavid du Colombier */
18101a344a2SDavid du Colombier static Side*
wormunit(Device * d)18201a344a2SDavid du Colombier wormunit(Device *d) /* d is l0 or r2 (e.g.) */
18301a344a2SDavid du Colombier {
18401a344a2SDavid du Colombier int p, drive;
18501a344a2SDavid du Colombier Device *dr; /* w0 or w1.2.0 (e.g.) */
18601a344a2SDavid du Colombier Side *v;
18701a344a2SDavid du Colombier Juke *w;
18801a344a2SDavid du Colombier Dir *dir;
18901a344a2SDavid du Colombier
19001a344a2SDavid du Colombier w = d->private;
19101a344a2SDavid du Colombier if (w == nil)
19201a344a2SDavid du Colombier panic("wormunit %Z nil juke", d);
19301a344a2SDavid du Colombier if (w->magic != Jukemagic)
19401a344a2SDavid du Colombier panic("bad magic in Juke for %Z", d);
19501a344a2SDavid du Colombier p = d->wren.targ;
19601a344a2SDavid du Colombier if(p < 0 || w && p >= w->nside) {
19701a344a2SDavid du Colombier panic("wormunit: target %d out of range for %Z", p, d);
19801a344a2SDavid du Colombier return 0;
19901a344a2SDavid du Colombier }
20001a344a2SDavid du Colombier
20101a344a2SDavid du Colombier /*
20201a344a2SDavid du Colombier * if disk is unloaded, must load it
20301a344a2SDavid du Colombier * into next (circular) logical unit
20401a344a2SDavid du Colombier */
20501a344a2SDavid du Colombier v = &w->side[p];
20601a344a2SDavid du Colombier qlock(v);
20701a344a2SDavid du Colombier if(v->status == Sunload) {
20801a344a2SDavid du Colombier for(;;) {
20901a344a2SDavid du Colombier qlock(w);
21001a344a2SDavid du Colombier drive = bestdrive(w, p);
21101a344a2SDavid du Colombier if(drive >= 0)
21201a344a2SDavid du Colombier break;
21301a344a2SDavid du Colombier qunlock(w);
21401a344a2SDavid du Colombier delay(100);
21501a344a2SDavid du Colombier }
21601a344a2SDavid du Colombier print("\tload r%ld drive %Z\n", v-w->side, w->drive[drive]);
21701a344a2SDavid du Colombier if(mmove(w, w->mt0, v->elem, w->dt0+drive, v->rot)) {
21801a344a2SDavid du Colombier qunlock(w);
21901a344a2SDavid du Colombier goto sbad;
22001a344a2SDavid du Colombier }
22101a344a2SDavid du Colombier v->drive = drive;
22201a344a2SDavid du Colombier v->status = Sstart;
22301a344a2SDavid du Colombier v->stime = toytime();
22401a344a2SDavid du Colombier qunlock(w);
22501a344a2SDavid du Colombier dr = w->drive[drive];
22601a344a2SDavid du Colombier if (!waitready(w, dr))
22701a344a2SDavid du Colombier goto sbad;
22801a344a2SDavid du Colombier v->stime = toytime();
22901a344a2SDavid du Colombier } else
23001a344a2SDavid du Colombier dr = w->drive[v->drive];
23101a344a2SDavid du Colombier if(v->status != Sstart) {
23201a344a2SDavid du Colombier if(v->status == Sempty)
23301a344a2SDavid du Colombier print("worm: unit empty %Z\n", d);
23401a344a2SDavid du Colombier else
23501a344a2SDavid du Colombier print("worm: not started %Z\n", d);
23601a344a2SDavid du Colombier goto sbad;
23701a344a2SDavid du Colombier }
23801a344a2SDavid du Colombier
23901a344a2SDavid du Colombier v->time = toytime();
24001a344a2SDavid du Colombier if(v->block) /* side is known already */
24101a344a2SDavid du Colombier return v;
24201a344a2SDavid du Colombier
24301a344a2SDavid du Colombier /*
24401a344a2SDavid du Colombier * load and record information about side
24501a344a2SDavid du Colombier */
24601a344a2SDavid du Colombier
24701a344a2SDavid du Colombier if (dr->wren.file)
24801a344a2SDavid du Colombier dr->wren.sddata = dataof(dr->wren.file);
24901a344a2SDavid du Colombier else {
25001a344a2SDavid du Colombier if (dr->wren.sddir == nil) {
25101a344a2SDavid du Colombier if (dr->type == Devwren)
25201a344a2SDavid du Colombier dr->wren.sddir = sdof(dr);
25301a344a2SDavid du Colombier if (dr->wren.sddir == nil)
25401a344a2SDavid du Colombier panic("wormunit: %Z for %Z not a wren", dr, d);
25501a344a2SDavid du Colombier }
25601a344a2SDavid du Colombier dr->wren.sddata = smprint("%s/data", dr->wren.sddir);
25701a344a2SDavid du Colombier }
25801a344a2SDavid du Colombier
25901a344a2SDavid du Colombier if (dr->wren.fd == 0)
26001a344a2SDavid du Colombier dr->wren.fd = open(dr->wren.sddata, ORDWR);
26101a344a2SDavid du Colombier if (dr->wren.fd < 0) {
26201a344a2SDavid du Colombier print("wormunit: can't open %s for %Z: %r\n", dr->wren.sddata, d);
26301a344a2SDavid du Colombier goto sbad;
26401a344a2SDavid du Colombier }
26501a344a2SDavid du Colombier
26601a344a2SDavid du Colombier v->block = inqsize(dr->wren.sddata);
26701a344a2SDavid du Colombier if(v->block <= 0) {
26801a344a2SDavid du Colombier print("\twormunit %Z block size %ld, setting to %d\n",
26901a344a2SDavid du Colombier d, v->block, Sectorsz);
27001a344a2SDavid du Colombier v->block = Sectorsz;
27101a344a2SDavid du Colombier }
27201a344a2SDavid du Colombier
27301a344a2SDavid du Colombier dir = dirfstat(dr->wren.fd);
27401a344a2SDavid du Colombier v->nblock = dir->length / v->block;
27501a344a2SDavid du Colombier free(dir);
27601a344a2SDavid du Colombier
27701a344a2SDavid du Colombier v->mult = (RBUFSIZE + v->block - 1) / v->block;
27801a344a2SDavid du Colombier v->max = (v->nblock + 1) / v->mult;
27901a344a2SDavid du Colombier
28001a344a2SDavid du Colombier print("\tworm %Z: drive %Z (juke drive %d)\n",
28101a344a2SDavid du Colombier d, w->drive[v->drive], v->drive);
28201a344a2SDavid du Colombier print("\t\t%,ld %ld-byte sectors, ", v->nblock, v->block);
28301a344a2SDavid du Colombier print("%,ld %d-byte blocks\n", v->max, RBUFSIZE);
28401a344a2SDavid du Colombier print("\t\t%ld multiplier\n", v->mult);
28501a344a2SDavid du Colombier if(d->type == Devlworm)
28601a344a2SDavid du Colombier return wormlabel(d, v);
28701a344a2SDavid du Colombier else
28801a344a2SDavid du Colombier return v;
28901a344a2SDavid du Colombier
29001a344a2SDavid du Colombier sbad:
29101a344a2SDavid du Colombier qunlock(v);
29201a344a2SDavid du Colombier return 0;
29301a344a2SDavid du Colombier }
29401a344a2SDavid du Colombier
29501a344a2SDavid du Colombier /* wait 10s for optical drive to spin up */
29601a344a2SDavid du Colombier static int
waitready(Juke * w,Device * d)29701a344a2SDavid du Colombier waitready(Juke *w, Device *d)
29801a344a2SDavid du Colombier {
29901a344a2SDavid du Colombier int p, e, rv;
30001a344a2SDavid du Colombier char *datanm;
30101a344a2SDavid du Colombier
30201a344a2SDavid du Colombier if (w->magic != Jukemagic)
30301a344a2SDavid du Colombier panic("waitready: bad magic in Juke (d->private) for %Z", d);
30401a344a2SDavid du Colombier p = d->wren.targ;
30501a344a2SDavid du Colombier if(p < 0 || p >= w->nside) {
30601a344a2SDavid du Colombier print("waitready: target %d out of range for %Z\n", p, d);
30701a344a2SDavid du Colombier return 0;
30801a344a2SDavid du Colombier }
30901a344a2SDavid du Colombier
31001a344a2SDavid du Colombier if (d->type == Devwren && d->wren.file)
31101a344a2SDavid du Colombier datanm = strdup(d->wren.file);
31201a344a2SDavid du Colombier else {
31301a344a2SDavid du Colombier if (d->wren.sddir)
31401a344a2SDavid du Colombier free(d->wren.sddir);
31501a344a2SDavid du Colombier if (d->type == Devwren)
31601a344a2SDavid du Colombier d->wren.sddir = sdof(d);
31701a344a2SDavid du Colombier if (d->wren.sddir == nil)
31801a344a2SDavid du Colombier panic("waitready: d->wren.sddir not set for %Z", d);
31901a344a2SDavid du Colombier
32001a344a2SDavid du Colombier datanm = smprint("%s/data", d->wren.sddir);
32101a344a2SDavid du Colombier }
32201a344a2SDavid du Colombier
32301a344a2SDavid du Colombier rv = 0;
32401a344a2SDavid du Colombier for(e=0; e < 100; e++) {
32501a344a2SDavid du Colombier if (e == 10)
32601a344a2SDavid du Colombier print("waitready: waiting for %s to exist\n", datanm); // DEBUG
32701a344a2SDavid du Colombier if (access(datanm, AEXIST) >= 0) {
32801a344a2SDavid du Colombier rv = 1;
32901a344a2SDavid du Colombier break;
33001a344a2SDavid du Colombier }
33101a344a2SDavid du Colombier delay(200);
33201a344a2SDavid du Colombier }
33301a344a2SDavid du Colombier if (rv == 0)
33401a344a2SDavid du Colombier print("waitready: %s for %Z didn't come ready\n", datanm, d);
33501a344a2SDavid du Colombier free(datanm);
33601a344a2SDavid du Colombier return rv;
33701a344a2SDavid du Colombier }
33801a344a2SDavid du Colombier
33901a344a2SDavid du Colombier static int
bestdrive(Juke * w,int side)34001a344a2SDavid du Colombier bestdrive(Juke *w, int side)
34101a344a2SDavid du Colombier {
34201a344a2SDavid du Colombier Side *v, *bv[MAXDRIVE];
34301a344a2SDavid du Colombier int i, e, drive;
34401a344a2SDavid du Colombier Timet t, t0;
34501a344a2SDavid du Colombier
34601a344a2SDavid du Colombier loop:
34701a344a2SDavid du Colombier /* build table of what platters on what drives */
34801a344a2SDavid du Colombier for(i=0; i<w->ndt; i++)
34901a344a2SDavid du Colombier bv[i] = 0;
35001a344a2SDavid du Colombier
35101a344a2SDavid du Colombier v = &w->side[0];
35201a344a2SDavid du Colombier for(i=0; i < w->nside; i++, v++)
35301a344a2SDavid du Colombier if(v->status == Sstart) {
35401a344a2SDavid du Colombier drive = v->drive;
35501a344a2SDavid du Colombier if(drive >= 0 && drive < w->ndt)
35601a344a2SDavid du Colombier bv[drive] = v;
35701a344a2SDavid du Colombier }
35801a344a2SDavid du Colombier
35901a344a2SDavid du Colombier /*
36001a344a2SDavid du Colombier * find oldest drive, but must be
36101a344a2SDavid du Colombier * at least THYSTER old.
36201a344a2SDavid du Colombier */
36301a344a2SDavid du Colombier e = w->side[side].elem;
36401a344a2SDavid du Colombier t0 = toytime() - THYSTER;
36501a344a2SDavid du Colombier t = t0;
36601a344a2SDavid du Colombier drive = -1;
36701a344a2SDavid du Colombier for(i=0; i<w->ndt; i++) {
36801a344a2SDavid du Colombier v = bv[i];
36901a344a2SDavid du Colombier if(v == 0) { /* 2nd priority: empty drive */
37001a344a2SDavid du Colombier if(w->offline[i])
37101a344a2SDavid du Colombier continue;
37201a344a2SDavid du Colombier if(w->drive[i] != devnone) {
37301a344a2SDavid du Colombier drive = i;
37401a344a2SDavid du Colombier t = 0;
37501a344a2SDavid du Colombier }
37601a344a2SDavid du Colombier continue;
37701a344a2SDavid du Colombier }
37801a344a2SDavid du Colombier if(v->elem == e) { /* 1st priority: other side */
37901a344a2SDavid du Colombier drive = -1;
38001a344a2SDavid du Colombier if(v->stime < t0)
38101a344a2SDavid du Colombier drive = i;
38201a344a2SDavid du Colombier break;
38301a344a2SDavid du Colombier }
38401a344a2SDavid du Colombier if(v->stime < t) { /* 3rd priority: by time */
38501a344a2SDavid du Colombier drive = i;
38601a344a2SDavid du Colombier t = v->stime;
38701a344a2SDavid du Colombier }
38801a344a2SDavid du Colombier }
38901a344a2SDavid du Colombier
39001a344a2SDavid du Colombier if(drive >= 0) {
39101a344a2SDavid du Colombier v = bv[drive];
39201a344a2SDavid du Colombier if(v) {
39301a344a2SDavid du Colombier qlock(v);
39401a344a2SDavid du Colombier if(v->status != Sstart) {
39501a344a2SDavid du Colombier qunlock(v);
39601a344a2SDavid du Colombier goto loop;
39701a344a2SDavid du Colombier }
39801a344a2SDavid du Colombier print("\tunload r%ld drive %Z\n",
39901a344a2SDavid du Colombier v-w->side, w->drive[drive]);
40001a344a2SDavid du Colombier if(mmove(w, w->mt0, w->dt0+drive, v->elem, v->rot)) {
40101a344a2SDavid du Colombier qunlock(v);
40201a344a2SDavid du Colombier goto loop;
40301a344a2SDavid du Colombier }
40401a344a2SDavid du Colombier v->status = Sunload;
40501a344a2SDavid du Colombier qunlock(v);
40601a344a2SDavid du Colombier }
40701a344a2SDavid du Colombier }
40801a344a2SDavid du Colombier return drive;
40901a344a2SDavid du Colombier }
41001a344a2SDavid du Colombier
41101a344a2SDavid du Colombier Devsize
wormsize(Device * d)41201a344a2SDavid du Colombier wormsize(Device *d)
41301a344a2SDavid du Colombier {
41401a344a2SDavid du Colombier Side *v;
41501a344a2SDavid du Colombier Juke *w;
41601a344a2SDavid du Colombier Devsize size;
41701a344a2SDavid du Colombier
41801a344a2SDavid du Colombier w = d->private;
41901a344a2SDavid du Colombier if (w->magic != Jukemagic)
42001a344a2SDavid du Colombier print("wormsize: bad magic in Juke (d->private) for %Z\n", d);
42101a344a2SDavid du Colombier if(w->isfixedsize && w->fixedsize != 0)
42201a344a2SDavid du Colombier size = w->fixedsize; /* fixed size is now known */
42301a344a2SDavid du Colombier else {
42401a344a2SDavid du Colombier if (w != d->private)
42501a344a2SDavid du Colombier panic("wormsize: w != %Z->private", d);
42601a344a2SDavid du Colombier v = wormunit(d);
42701a344a2SDavid du Colombier if(v == nil)
42801a344a2SDavid du Colombier return 0;
42901a344a2SDavid du Colombier size = v->max;
43001a344a2SDavid du Colombier qunlock(v);
43101a344a2SDavid du Colombier /*
43201a344a2SDavid du Colombier * set fixed size for whole Juke from
43301a344a2SDavid du Colombier * size of first disc examined.
43401a344a2SDavid du Colombier */
43501a344a2SDavid du Colombier if(w->isfixedsize)
43601a344a2SDavid du Colombier w->fixedsize = size;
43701a344a2SDavid du Colombier }
43801a344a2SDavid du Colombier if(d->type == Devlworm)
43901a344a2SDavid du Colombier return size-1; /* lie: last block is for label */
44001a344a2SDavid du Colombier return size;
44101a344a2SDavid du Colombier }
44201a344a2SDavid du Colombier
44301a344a2SDavid du Colombier /*
44401a344a2SDavid du Colombier * return a Devjuke or an mcat (normally of sides) from within d (or nil).
44501a344a2SDavid du Colombier * if it's an mcat, the caller must walk it.
44601a344a2SDavid du Colombier */
44701a344a2SDavid du Colombier static Device *
devtojuke(Device * d,Device * top)44801a344a2SDavid du Colombier devtojuke(Device *d, Device *top)
44901a344a2SDavid du Colombier {
45001a344a2SDavid du Colombier while (d != nil)
45101a344a2SDavid du Colombier switch(d->type) {
45201a344a2SDavid du Colombier default:
45301a344a2SDavid du Colombier print("devtojuke: type of device %Z of %Z unknown\n",
45401a344a2SDavid du Colombier d, top);
45501a344a2SDavid du Colombier return nil;
45601a344a2SDavid du Colombier
45701a344a2SDavid du Colombier case Devjuke:
45801a344a2SDavid du Colombier /* jackpot! d->private is a (Juke *) with nside, &c. */
45901a344a2SDavid du Colombier /* FALL THROUGH */
46001a344a2SDavid du Colombier case Devmcat:
46101a344a2SDavid du Colombier case Devmlev:
46201a344a2SDavid du Colombier case Devmirr:
46301a344a2SDavid du Colombier /* squint hard & call an mlev or a mirr an mcat */
46401a344a2SDavid du Colombier return d;
46501a344a2SDavid du Colombier
46601a344a2SDavid du Colombier case Devworm:
46701a344a2SDavid du Colombier case Devlworm:
46801a344a2SDavid du Colombier /*
46901a344a2SDavid du Colombier * d->private is a (Juke *) with nside, etc.,
47001a344a2SDavid du Colombier * but we're not supposed to get here.
47101a344a2SDavid du Colombier */
47201a344a2SDavid du Colombier print("devtojuke: (l)worm %Z of %Z encountered\n",
47301a344a2SDavid du Colombier d, top);
47401a344a2SDavid du Colombier /* FALL THROUGH */
47501a344a2SDavid du Colombier case Devwren:
47601a344a2SDavid du Colombier return nil;
47701a344a2SDavid du Colombier
47801a344a2SDavid du Colombier case Devcw:
47901a344a2SDavid du Colombier d = d->cw.w; /* usually juke */
48001a344a2SDavid du Colombier break;
48101a344a2SDavid du Colombier case Devro:
48201a344a2SDavid du Colombier d = d->ro.parent; /* cw */
48301a344a2SDavid du Colombier break;
48401a344a2SDavid du Colombier case Devfworm:
48501a344a2SDavid du Colombier d = d->fw.fw;
48601a344a2SDavid du Colombier break;
48701a344a2SDavid du Colombier case Devpart:
48801a344a2SDavid du Colombier d = d->part.d;
48901a344a2SDavid du Colombier break;
49001a344a2SDavid du Colombier case Devswab:
49101a344a2SDavid du Colombier d = d->swab.d;
49201a344a2SDavid du Colombier break;
49301a344a2SDavid du Colombier }
49401a344a2SDavid du Colombier return d;
49501a344a2SDavid du Colombier }
49601a344a2SDavid du Colombier
49701a344a2SDavid du Colombier static int
devisside(Device * d)49801a344a2SDavid du Colombier devisside(Device *d)
49901a344a2SDavid du Colombier {
50001a344a2SDavid du Colombier return d->type == Devworm || d->type == Devlworm;
50101a344a2SDavid du Colombier }
50201a344a2SDavid du Colombier
50301a344a2SDavid du Colombier static Device *
findside(Device * juke,int side,Device * top)50401a344a2SDavid du Colombier findside(Device *juke, int side, Device *top)
50501a344a2SDavid du Colombier {
50601a344a2SDavid du Colombier int i = 0;
50701a344a2SDavid du Colombier Device *mcat = juke->j.m, *x;
50801a344a2SDavid du Colombier Juke *w = juke->private;
50901a344a2SDavid du Colombier
51001a344a2SDavid du Colombier for (x = mcat->cat.first; x != nil; x = x->link) {
51101a344a2SDavid du Colombier if (!devisside(x)) {
51201a344a2SDavid du Colombier print("wormsizeside: %Z of %Z of %Z type not (l)worm\n",
51301a344a2SDavid du Colombier x, mcat, top);
51401a344a2SDavid du Colombier return nil;
51501a344a2SDavid du Colombier }
51601a344a2SDavid du Colombier i = x->wren.targ;
51701a344a2SDavid du Colombier if (i < 0 || i >= w->nside)
51801a344a2SDavid du Colombier panic("wormsizeside: side %d in %Z out of range",
51901a344a2SDavid du Colombier i, mcat);
52001a344a2SDavid du Colombier if (i == side)
52101a344a2SDavid du Colombier break;
52201a344a2SDavid du Colombier }
52301a344a2SDavid du Colombier if (x == nil)
52401a344a2SDavid du Colombier return nil;
52501a344a2SDavid du Colombier if (w->side[i].time == 0) {
52601a344a2SDavid du Colombier print("wormsizeside: side %d not in jukebox %Z\n", i, juke);
52701a344a2SDavid du Colombier return nil;
52801a344a2SDavid du Colombier }
52901a344a2SDavid du Colombier return x;
53001a344a2SDavid du Colombier }
53101a344a2SDavid du Colombier
53201a344a2SDavid du Colombier typedef struct {
53301a344a2SDavid du Colombier int sleft; /* sides still to visit to reach desired side */
53401a344a2SDavid du Colombier int starget; /* side of topdev we want */
53501a344a2SDavid du Colombier Device *topdev;
53601a344a2SDavid du Colombier int sawjuke; /* passed by a jukebox */
53701a344a2SDavid du Colombier int sized; /* flag: asked wormsize for size of starget */
53801a344a2SDavid du Colombier } Visit;
53901a344a2SDavid du Colombier
54001a344a2SDavid du Colombier /*
54101a344a2SDavid du Colombier * walk the Device tree from d looking for Devjukes, counting sides.
54201a344a2SDavid du Colombier * the main complication is mcats and the like with Devjukes in them.
54301a344a2SDavid du Colombier * use Devjuke's d->private as Juke* and see sides.
54401a344a2SDavid du Colombier */
54501a344a2SDavid du Colombier static Off
visitsides(Device * d,Device * parentj,Visit * vp)54601a344a2SDavid du Colombier visitsides(Device *d, Device *parentj, Visit *vp)
54701a344a2SDavid du Colombier {
54801a344a2SDavid du Colombier Off size = 0;
54901a344a2SDavid du Colombier Device *x;
55001a344a2SDavid du Colombier Juke *w;
55101a344a2SDavid du Colombier
55201a344a2SDavid du Colombier /*
55301a344a2SDavid du Colombier * find the first juke or mcat.
55401a344a2SDavid du Colombier * d==nil means we couldn't find one; typically harmless, due to a
55501a344a2SDavid du Colombier * mirror of dissimilar devices.
55601a344a2SDavid du Colombier */
55701a344a2SDavid du Colombier d = devtojuke(d, vp->topdev);
55801a344a2SDavid du Colombier if (d == nil || vp->sleft < 0)
55901a344a2SDavid du Colombier return 0;
56001a344a2SDavid du Colombier if (d->type == Devjuke) { /* jackpot! d->private is a (Juke *) */
56101a344a2SDavid du Colombier vp->sawjuke = 1;
56201a344a2SDavid du Colombier w = d->private;
56301a344a2SDavid du Colombier /*
56401a344a2SDavid du Colombier * if there aren't enough sides in this jukebox to reach
56501a344a2SDavid du Colombier * the desired one, subtract these sides and pass.
56601a344a2SDavid du Colombier */
56701a344a2SDavid du Colombier if (vp->sleft >= w->nside) {
56801a344a2SDavid du Colombier vp->sleft -= w->nside;
56901a344a2SDavid du Colombier return 0;
57001a344a2SDavid du Colombier }
57101a344a2SDavid du Colombier /* else this is the right juke, paw through mcat of sides */
57201a344a2SDavid du Colombier return visitsides(d->j.m, d, vp);
57301a344a2SDavid du Colombier }
57401a344a2SDavid du Colombier
57501a344a2SDavid du Colombier /*
57601a344a2SDavid du Colombier * d will usually be an mcat of sides, but it could be an mcat of
57701a344a2SDavid du Colombier * jukes, for example. in that case, we need to walk the mcat,
57801a344a2SDavid du Colombier * recursing as needed, until we find the right juke, then stop at
57901a344a2SDavid du Colombier * the right side within its mcat of sides, by comparing side
58001a344a2SDavid du Colombier * numbers, not just by counting (to allow for unused slots).
58101a344a2SDavid du Colombier */
58201a344a2SDavid du Colombier x = d->cat.first;
58301a344a2SDavid du Colombier if (x == nil) {
58401a344a2SDavid du Colombier print("visitsides: %Z of %Z: empty mcat\n", d, vp->topdev);
58501a344a2SDavid du Colombier return 0;
58601a344a2SDavid du Colombier }
58701a344a2SDavid du Colombier if (!devisside(x)) {
58801a344a2SDavid du Colombier for (; x != nil && !vp->sized; x = x->link)
58901a344a2SDavid du Colombier size = visitsides(x, parentj, vp);
59001a344a2SDavid du Colombier return size;
59101a344a2SDavid du Colombier }
59201a344a2SDavid du Colombier
59301a344a2SDavid du Colombier /* the side we want is in this jukebox, thus this mcat (d) */
59401a344a2SDavid du Colombier if (parentj == nil) {
59501a344a2SDavid du Colombier print("visitsides: no parent juke for sides mcat %Z\n", d);
59601a344a2SDavid du Colombier vp->sleft = -1;
59701a344a2SDavid du Colombier return 0;
59801a344a2SDavid du Colombier }
59901a344a2SDavid du Colombier if (d != parentj->j.m)
60001a344a2SDavid du Colombier panic("visitsides: mcat mismatch %Z vs %Z", d, parentj->j.m);
60101a344a2SDavid du Colombier x = findside(parentj, vp->sleft, vp->topdev);
60201a344a2SDavid du Colombier if (x == nil) {
60301a344a2SDavid du Colombier vp->sleft = -1;
60401a344a2SDavid du Colombier return 0;
60501a344a2SDavid du Colombier }
60601a344a2SDavid du Colombier
60701a344a2SDavid du Colombier /* we've turned vp->starget into the right Device* */
60801a344a2SDavid du Colombier vp->sleft = 0;
60901a344a2SDavid du Colombier vp->sized = 1;
61001a344a2SDavid du Colombier return wormsize(x);
61101a344a2SDavid du Colombier }
61201a344a2SDavid du Colombier
61301a344a2SDavid du Colombier /*
61401a344a2SDavid du Colombier * d must be, or be within, a filesystem config that also contains
61501a344a2SDavid du Colombier * the jukebox that `side' resides on.
61601a344a2SDavid du Colombier * d is normally a Devcw, but could be Devwren, Devide, Devpart, Devfworm,
61701a344a2SDavid du Colombier * etc. if called from chk.c Ctouch code. Note too that the worm part of
61801a344a2SDavid du Colombier * the Devcw might be other than a Devjuke.
61901a344a2SDavid du Colombier */
62001a344a2SDavid du Colombier Devsize
wormsizeside(Device * d,int side)62101a344a2SDavid du Colombier wormsizeside(Device *d, int side)
62201a344a2SDavid du Colombier {
62301a344a2SDavid du Colombier Devsize size;
62401a344a2SDavid du Colombier Visit visit;
62501a344a2SDavid du Colombier
62601a344a2SDavid du Colombier memset(&visit, 0, sizeof visit);
62701a344a2SDavid du Colombier visit.starget = visit.sleft = side;
62801a344a2SDavid du Colombier visit.topdev = d;
62901a344a2SDavid du Colombier size = visitsides(d, nil, &visit);
63001a344a2SDavid du Colombier if (visit.sawjuke && (visit.sleft != 0 || !visit.sized)) {
63101a344a2SDavid du Colombier print("wormsizeside: fewer than %d sides in %Z\n", side, d);
63201a344a2SDavid du Colombier return 0;
63301a344a2SDavid du Colombier }
63401a344a2SDavid du Colombier return size;
63501a344a2SDavid du Colombier }
63601a344a2SDavid du Colombier
63701a344a2SDavid du Colombier /*
63801a344a2SDavid du Colombier * returns starts (in blocks) of side #side and #(side+1) of dev in *stp.
63901a344a2SDavid du Colombier * dev should be a Devcw.
64001a344a2SDavid du Colombier */
64101a344a2SDavid du Colombier void
wormsidestarts(Device * dev,int side,Sidestarts * stp)64201a344a2SDavid du Colombier wormsidestarts(Device *dev, int side, Sidestarts *stp)
64301a344a2SDavid du Colombier {
64401a344a2SDavid du Colombier int s;
64501a344a2SDavid du Colombier Devsize dstart;
64601a344a2SDavid du Colombier
64701a344a2SDavid du Colombier for (dstart = s = 0; s < side; s++)
64801a344a2SDavid du Colombier dstart += wormsizeside(dev, s);
64901a344a2SDavid du Colombier stp->sstart = dstart;
65001a344a2SDavid du Colombier stp->s1start = dstart + wormsizeside(dev, side);
65101a344a2SDavid du Colombier }
65201a344a2SDavid du Colombier
65301a344a2SDavid du Colombier int
wormread(Device * d,Off b,void * c)65401a344a2SDavid du Colombier wormread(Device *d, Off b, void *c)
65501a344a2SDavid du Colombier {
65601a344a2SDavid du Colombier int r = 0;
65701a344a2SDavid du Colombier long max;
65801a344a2SDavid du Colombier char name[128];
65901a344a2SDavid du Colombier Side *v = wormunit(d);
66001a344a2SDavid du Colombier Juke *w = d->private;
66101a344a2SDavid du Colombier Device *dr;
66201a344a2SDavid du Colombier
66301a344a2SDavid du Colombier if (v == nil)
66401a344a2SDavid du Colombier panic("wormread: nil wormunit(%Z)", d);
66501a344a2SDavid du Colombier dr = w->drive[v->drive];
66601a344a2SDavid du Colombier if (dr->wren.fd < 0)
66701a344a2SDavid du Colombier panic("wormread: unopened fd for %Z", d);
66801a344a2SDavid du Colombier max = (d->type == Devlworm? v->max + 1: v->max);
66901a344a2SDavid du Colombier if(b >= max) {
67001a344a2SDavid du Colombier print("wormread: block out of range %Z(%lld)\n", d, (Wideoff)b);
67101a344a2SDavid du Colombier r = 0x071;
672*390ad7e1SDavid du Colombier } else if (pread(dr->wren.fd, c, RBUFSIZE, (vlong)b*RBUFSIZE) != RBUFSIZE) {
67301a344a2SDavid du Colombier fd2path(dr->wren.fd, name, sizeof name);
67401a344a2SDavid du Colombier print("wormread: error on %Z(%lld) on %s in %s: %r\n",
67501a344a2SDavid du Colombier d, (Wideoff)b, name, dr->wren.sddir);
67601a344a2SDavid du Colombier cons.nwormre++;
67701a344a2SDavid du Colombier r = 1;
67801a344a2SDavid du Colombier }
67901a344a2SDavid du Colombier qunlock(v);
68001a344a2SDavid du Colombier return r;
68101a344a2SDavid du Colombier }
68201a344a2SDavid du Colombier
68301a344a2SDavid du Colombier int
wormwrite(Device * d,Off b,void * c)68401a344a2SDavid du Colombier wormwrite(Device *d, Off b, void *c)
68501a344a2SDavid du Colombier {
68601a344a2SDavid du Colombier int r = 0;
68701a344a2SDavid du Colombier long max;
68801a344a2SDavid du Colombier char name[128];
68901a344a2SDavid du Colombier Side *v = wormunit(d);
69001a344a2SDavid du Colombier Juke *w = d->private;
69101a344a2SDavid du Colombier Device *dr;
69201a344a2SDavid du Colombier
69301a344a2SDavid du Colombier if (v == nil)
69401a344a2SDavid du Colombier panic("wormwrite: nil wormunit(%Z)", d);
69501a344a2SDavid du Colombier dr = w->drive[v->drive];
69601a344a2SDavid du Colombier if (dr->wren.fd < 0)
69701a344a2SDavid du Colombier panic("wormwrite: unopened fd for %Z", d);
69801a344a2SDavid du Colombier max = (d->type == Devlworm? v->max + 1: v->max);
69901a344a2SDavid du Colombier if(b >= max) {
70001a344a2SDavid du Colombier print("wormwrite: block out of range %Z(%lld)\n",
70101a344a2SDavid du Colombier d, (Wideoff)b);
70201a344a2SDavid du Colombier r = 0x071;
703*390ad7e1SDavid du Colombier } else if (pwrite(dr->wren.fd, c, RBUFSIZE, (vlong)b*RBUFSIZE) != RBUFSIZE) {
70401a344a2SDavid du Colombier fd2path(dr->wren.fd, name, sizeof name);
70501a344a2SDavid du Colombier print("wormwrwite: error on %Z(%lld) on %s in %s: %r\n",
70601a344a2SDavid du Colombier d, (Wideoff)b, name, dr->wren.sddir);
70701a344a2SDavid du Colombier cons.nwormwe++;
70801a344a2SDavid du Colombier r = 1;
70901a344a2SDavid du Colombier }
71001a344a2SDavid du Colombier qunlock(v);
71101a344a2SDavid du Colombier return r;
71201a344a2SDavid du Colombier }
71301a344a2SDavid du Colombier
71401a344a2SDavid du Colombier static int
mmove(Juke * w,int trans,int from,int to,int rot)71501a344a2SDavid du Colombier mmove(Juke *w, int trans, int from, int to, int rot)
71601a344a2SDavid du Colombier {
71701a344a2SDavid du Colombier int s;
71801a344a2SDavid du Colombier uchar cmd[12], buf[4];
71901a344a2SDavid du Colombier static int recur = 0;
72001a344a2SDavid du Colombier
72101a344a2SDavid du Colombier memset(cmd, 0, sizeof cmd);
72201a344a2SDavid du Colombier cmd[0] = 0xa5; /* move medium */
72301a344a2SDavid du Colombier cmd[2] = trans>>8;
72401a344a2SDavid du Colombier cmd[3] = trans;
72501a344a2SDavid du Colombier cmd[4] = from>>8;
72601a344a2SDavid du Colombier cmd[5] = from;
72701a344a2SDavid du Colombier cmd[6] = to>>8;
72801a344a2SDavid du Colombier cmd[7] = to;
72901a344a2SDavid du Colombier if(rot)
73001a344a2SDavid du Colombier cmd[10] = 1;
73101a344a2SDavid du Colombier s = scsiio(w->juke, SCSInone, cmd, sizeof cmd, buf, 0); /* mmove */
73201a344a2SDavid du Colombier if(s) {
73301a344a2SDavid du Colombier print("scsio status #%x\n", s);
73401a344a2SDavid du Colombier print("move medium t=%d fr=%d to=%d rot=%d\n",
73501a344a2SDavid du Colombier trans, from, to, rot);
73601a344a2SDavid du Colombier // panic("mmove");
73701a344a2SDavid du Colombier if(recur == 0) {
73801a344a2SDavid du Colombier recur = 1;
73901a344a2SDavid du Colombier print("element from=%d\n", from);
74001a344a2SDavid du Colombier element(w, from);
74101a344a2SDavid du Colombier print("element to=%d\n", to);
74201a344a2SDavid du Colombier element(w, to);
74301a344a2SDavid du Colombier print("element trans=%d\n", trans);
74401a344a2SDavid du Colombier element(w, trans);
74501a344a2SDavid du Colombier recur = 0;
74601a344a2SDavid du Colombier }
74701a344a2SDavid du Colombier return 1;
74801a344a2SDavid du Colombier }
74901a344a2SDavid du Colombier return 0;
75001a344a2SDavid du Colombier }
75101a344a2SDavid du Colombier
75201a344a2SDavid du Colombier static void
geometry(Juke * w)75301a344a2SDavid du Colombier geometry(Juke *w)
75401a344a2SDavid du Colombier {
75501a344a2SDavid du Colombier int s;
75601a344a2SDavid du Colombier uchar cmd[6], buf[4+20];
75701a344a2SDavid du Colombier
75801a344a2SDavid du Colombier memset(cmd, 0, sizeof cmd);
75901a344a2SDavid du Colombier memset(buf, 0, sizeof buf);
76001a344a2SDavid du Colombier cmd[0] = 0x1a; /* mode sense */
76101a344a2SDavid du Colombier cmd[2] = 0x1d; /* element address assignment */
76201a344a2SDavid du Colombier cmd[4] = sizeof buf; /* allocation length */
76301a344a2SDavid du Colombier
76401a344a2SDavid du Colombier s = scsiio(w->juke, SCSIread, cmd, sizeof cmd, buf, sizeof buf); /* mode sense elem addrs */
76501a344a2SDavid du Colombier if(s)
76601a344a2SDavid du Colombier panic("geometry #%x", s);
76701a344a2SDavid du Colombier
76801a344a2SDavid du Colombier w->mt0 = (buf[4+2]<<8) | buf[4+3];
76901a344a2SDavid du Colombier w->nmt = (buf[4+4]<<8) | buf[4+5];
77001a344a2SDavid du Colombier w->se0 = (buf[4+6]<<8) | buf[4+7];
77101a344a2SDavid du Colombier w->nse = (buf[4+8]<<8) | buf[4+9];
77201a344a2SDavid du Colombier w->ie0 = (buf[4+10]<<8) | buf[4+11];
77301a344a2SDavid du Colombier w->nie = (buf[4+12]<<8) | buf[4+13];
77401a344a2SDavid du Colombier w->dt0 = (buf[4+14]<<8) | buf[4+15];
77501a344a2SDavid du Colombier w->ndt = (buf[4+16]<<8) | buf[4+17];
77601a344a2SDavid du Colombier
77701a344a2SDavid du Colombier memset(cmd, 0, 6);
77801a344a2SDavid du Colombier memset(buf, 0, sizeof buf);
77901a344a2SDavid du Colombier cmd[0] = 0x1a; /* mode sense */
78001a344a2SDavid du Colombier cmd[2] = 0x1e; /* transport geometry */
78101a344a2SDavid du Colombier cmd[4] = sizeof buf; /* allocation length */
78201a344a2SDavid du Colombier
78301a344a2SDavid du Colombier s = scsiio(w->juke, SCSIread, cmd, sizeof cmd, buf, sizeof buf); /* mode sense geometry */
78401a344a2SDavid du Colombier if(s)
78501a344a2SDavid du Colombier panic("geometry #%x", s);
78601a344a2SDavid du Colombier
78701a344a2SDavid du Colombier w->rot = buf[4+2] & 1;
78801a344a2SDavid du Colombier
78901a344a2SDavid du Colombier print("\tmt %d %d\n", w->mt0, w->nmt);
79001a344a2SDavid du Colombier print("\tse %d %d\n", w->se0, w->nse);
79101a344a2SDavid du Colombier print("\tie %d %d\n", w->ie0, w->nie);
79201a344a2SDavid du Colombier print("\tdt %d %d\n", w->dt0, w->ndt);
79301a344a2SDavid du Colombier print("\trot %d\n", w->rot);
79401a344a2SDavid du Colombier prflush();
79501a344a2SDavid du Colombier }
79601a344a2SDavid du Colombier
79701a344a2SDavid du Colombier /*
79801a344a2SDavid du Colombier * read element e's status from jukebox w, move any disc in drive back to its
79901a344a2SDavid du Colombier * slot, and update and print software status.
80001a344a2SDavid du Colombier */
80101a344a2SDavid du Colombier static void
element(Juke * w,int e)80201a344a2SDavid du Colombier element(Juke *w, int e)
80301a344a2SDavid du Colombier {
80401a344a2SDavid du Colombier uchar cmd[12], buf[8+8+88];
80501a344a2SDavid du Colombier int s, t;
80601a344a2SDavid du Colombier
80701a344a2SDavid du Colombier memset(cmd, 0, sizeof cmd);
80801a344a2SDavid du Colombier memset(buf, 0, sizeof buf);
80901a344a2SDavid du Colombier cmd[0] = 0xb8; /* read element status */
81001a344a2SDavid du Colombier cmd[2] = e>>8; /* starting element */
81101a344a2SDavid du Colombier cmd[3] = e;
81201a344a2SDavid du Colombier cmd[5] = 1; /* number of elements */
81301a344a2SDavid du Colombier cmd[9] = sizeof buf; /* allocation length */
81401a344a2SDavid du Colombier
81501a344a2SDavid du Colombier s = scsiio(w->juke, SCSIread, cmd, sizeof cmd, buf, sizeof buf); /* read elem sts */
81601a344a2SDavid du Colombier if(s) {
81701a344a2SDavid du Colombier print("scsiio #%x\n", s);
81801a344a2SDavid du Colombier goto bad;
81901a344a2SDavid du Colombier }
82001a344a2SDavid du Colombier
82101a344a2SDavid du Colombier s = (buf[0]<<8) | buf[1];
82201a344a2SDavid du Colombier if(s != e) {
82301a344a2SDavid du Colombier print("element = %d\n", s);
82401a344a2SDavid du Colombier goto bad;
82501a344a2SDavid du Colombier }
82601a344a2SDavid du Colombier if(buf[3] != 1) {
82701a344a2SDavid du Colombier print("number reported = %d\n", buf[3]);
82801a344a2SDavid du Colombier goto bad;
82901a344a2SDavid du Colombier }
83001a344a2SDavid du Colombier s = (buf[8+8+0]<<8) | buf[8+8+1];
83101a344a2SDavid du Colombier if(s != e) {
83201a344a2SDavid du Colombier print("element1 = %d\n", s);
83301a344a2SDavid du Colombier goto bad;
83401a344a2SDavid du Colombier }
83501a344a2SDavid du Colombier
83601a344a2SDavid du Colombier switch(buf[8+0]) { /* element type */
83701a344a2SDavid du Colombier default:
83801a344a2SDavid du Colombier print("unknown element %d: %d\n", e, buf[8+0]);
83901a344a2SDavid du Colombier goto bad;
84001a344a2SDavid du Colombier case 1: /* transport */
84101a344a2SDavid du Colombier s = e - w->mt0;
84201a344a2SDavid du Colombier if(s < 0 || s >= w->nmt)
84301a344a2SDavid du Colombier goto bad;
84401a344a2SDavid du Colombier if(buf[8+8+2] & 1)
84501a344a2SDavid du Colombier print("transport %d full %d.%d\n", s,
84601a344a2SDavid du Colombier (buf[8+8+10]<<8) | buf[8+8+11],
84701a344a2SDavid du Colombier (buf[8+8+9]>>6) & 1);
84801a344a2SDavid du Colombier break;
84901a344a2SDavid du Colombier case 2: /* storage */
85001a344a2SDavid du Colombier s = e - w->se0;
85101a344a2SDavid du Colombier if(s < 0 || s >= w->nse)
85201a344a2SDavid du Colombier goto bad;
85301a344a2SDavid du Colombier w->side[s].status = Sempty;
85401a344a2SDavid du Colombier if(buf[8+8+2] & 1)
85501a344a2SDavid du Colombier w->side[s].status = Sunload;
85601a344a2SDavid du Colombier if(w->rot)
85701a344a2SDavid du Colombier w->side[w->nse+s].status = w->side[s].status;
85801a344a2SDavid du Colombier break;
85901a344a2SDavid du Colombier case 3: /* import/export */
86001a344a2SDavid du Colombier s = e - w->ie0;
86101a344a2SDavid du Colombier if(s < 0 || s >= w->nie)
86201a344a2SDavid du Colombier goto bad;
86301a344a2SDavid du Colombier print("import/export %d #%.2x %d.%d\n", s,
86401a344a2SDavid du Colombier buf[8+8+2],
86501a344a2SDavid du Colombier (buf[8+8+10]<<8) | buf[8+8+11],
86601a344a2SDavid du Colombier (buf[8+8+9]>>6) & 1);
86701a344a2SDavid du Colombier break;
86801a344a2SDavid du Colombier case 4: /* data transfer */
86901a344a2SDavid du Colombier s = e - w->dt0;
87001a344a2SDavid du Colombier if(s < 0 || s >= w->ndt)
87101a344a2SDavid du Colombier goto bad;
87201a344a2SDavid du Colombier print("data transfer %d #%.2x %d.%d\n", s,
87301a344a2SDavid du Colombier buf[8+8+2],
87401a344a2SDavid du Colombier (buf[8+8+10]<<8) | buf[8+8+11],
87501a344a2SDavid du Colombier (buf[8+8+9]>>6) & 1);
87601a344a2SDavid du Colombier if(buf[8+8+2] & 1) {
87701a344a2SDavid du Colombier t = ((buf[8+8+10]<<8) | buf[8+8+11]) - w->se0;
87801a344a2SDavid du Colombier if (t < 0 || t >= w->nse || t >= MAXSIDE ||
87901a344a2SDavid du Colombier s >= MAXDRIVE) {
88001a344a2SDavid du Colombier print(
88101a344a2SDavid du Colombier "element: juke %Z lies; claims side %d is in drive %d\n",
88201a344a2SDavid du Colombier w->juke, t, s); /* lying sack of ... */
88301a344a2SDavid du Colombier /*
88401a344a2SDavid du Colombier * at minimum, we've avoided corrupting our
88501a344a2SDavid du Colombier * data structures. if we know that numbers
88601a344a2SDavid du Colombier * like w->nside are valid here, we could use
88701a344a2SDavid du Colombier * them in more stringent tests.
88801a344a2SDavid du Colombier * perhaps should whack the jukebox upside the
88901a344a2SDavid du Colombier * head here to knock some sense into it.
89001a344a2SDavid du Colombier */
89101a344a2SDavid du Colombier goto bad;
89201a344a2SDavid du Colombier }
89301a344a2SDavid du Colombier print("r%d in drive %d\n", t, s);
89401a344a2SDavid du Colombier if(mmove(w, w->mt0, w->dt0+s, w->se0+t,
89501a344a2SDavid du Colombier (buf[8+8+9]>>6) & 1)) {
89601a344a2SDavid du Colombier print("mmove initial unload\n");
89701a344a2SDavid du Colombier goto bad;
89801a344a2SDavid du Colombier }
89901a344a2SDavid du Colombier w->side[t].status = Sunload;
90001a344a2SDavid du Colombier if(w->rot)
90101a344a2SDavid du Colombier w->side[w->nse+t].status = Sunload;
90201a344a2SDavid du Colombier }
90301a344a2SDavid du Colombier if(buf[8+8+2] & 4) {
90401a344a2SDavid du Colombier print("drive w%d has exception #%.2x #%.2x\n", s,
90501a344a2SDavid du Colombier buf[8+8+4], buf[8+8+5]);
90601a344a2SDavid du Colombier goto bad;
90701a344a2SDavid du Colombier }
90801a344a2SDavid du Colombier break;
90901a344a2SDavid du Colombier }
91001a344a2SDavid du Colombier return;
91101a344a2SDavid du Colombier bad:
91201a344a2SDavid du Colombier /* panic("element") */ ;
91301a344a2SDavid du Colombier }
91401a344a2SDavid du Colombier
91501a344a2SDavid du Colombier /*
91601a344a2SDavid du Colombier * read all elements' status from jukebox w, move any discs in drives back
91701a344a2SDavid du Colombier * to their slots, and update and print software status.
91801a344a2SDavid du Colombier */
91901a344a2SDavid du Colombier static void
positions(Juke * w)92001a344a2SDavid du Colombier positions(Juke *w)
92101a344a2SDavid du Colombier {
92201a344a2SDavid du Colombier int i, f;
92301a344a2SDavid du Colombier
92401a344a2SDavid du Colombier /* mark empty shelves */
92501a344a2SDavid du Colombier for(i=0; i<w->nse; i++)
92601a344a2SDavid du Colombier element(w, w->se0+i);
92701a344a2SDavid du Colombier for(i=0; i<w->nmt; i++)
92801a344a2SDavid du Colombier element(w, w->mt0+i);
92901a344a2SDavid du Colombier for(i=0; i<w->nie; i++)
93001a344a2SDavid du Colombier element(w, w->ie0+i);
93101a344a2SDavid du Colombier for(i=0; i<w->ndt; i++)
93201a344a2SDavid du Colombier element(w, w->dt0+i);
93301a344a2SDavid du Colombier
93401a344a2SDavid du Colombier f = 0;
93501a344a2SDavid du Colombier for(i=0; i<w->nse; i++)
93601a344a2SDavid du Colombier if(w->side[i].status == Sempty) {
93701a344a2SDavid du Colombier if(f) {
93801a344a2SDavid du Colombier print("r%d\n", i-1);
93901a344a2SDavid du Colombier f = 0;
94001a344a2SDavid du Colombier }
94101a344a2SDavid du Colombier } else {
94201a344a2SDavid du Colombier if(!f) {
94301a344a2SDavid du Colombier print("\tshelves r%d-", i);
94401a344a2SDavid du Colombier f = 1;
94501a344a2SDavid du Colombier }
94601a344a2SDavid du Colombier }
94701a344a2SDavid du Colombier if(f)
94801a344a2SDavid du Colombier print("r%d\n", i-1);
94901a344a2SDavid du Colombier }
95001a344a2SDavid du Colombier
95101a344a2SDavid du Colombier static void
jinit(Juke * w,Device * d,int o)95201a344a2SDavid du Colombier jinit(Juke *w, Device *d, int o)
95301a344a2SDavid du Colombier {
95401a344a2SDavid du Colombier int p;
95501a344a2SDavid du Colombier Device *dev = d;
95601a344a2SDavid du Colombier
95701a344a2SDavid du Colombier switch(d->type) {
95801a344a2SDavid du Colombier default:
95901a344a2SDavid du Colombier print("juke platter not (devmcat of) dev(l)worm: %Z\n", d);
96001a344a2SDavid du Colombier panic("jinit: type");
96101a344a2SDavid du Colombier
96201a344a2SDavid du Colombier case Devmcat:
96301a344a2SDavid du Colombier /*
96401a344a2SDavid du Colombier * we don't call mcatinit(d) here, so we have to set d->cat.ndev
96501a344a2SDavid du Colombier * ourselves.
96601a344a2SDavid du Colombier */
96701a344a2SDavid du Colombier for(d=d->cat.first; d; d=d->link)
96801a344a2SDavid du Colombier jinit(w, d, o++);
96901a344a2SDavid du Colombier dev->cat.ndev = o;
97001a344a2SDavid du Colombier break;
97101a344a2SDavid du Colombier
97201a344a2SDavid du Colombier case Devlworm:
97301a344a2SDavid du Colombier p = d->wren.targ;
97401a344a2SDavid du Colombier if(p < 0 || p >= w->nside)
97501a344a2SDavid du Colombier panic("jinit partition %Z", d);
97601a344a2SDavid du Colombier w->side[p].ord = o;
97701a344a2SDavid du Colombier /* FALL THROUGH */
97801a344a2SDavid du Colombier case Devworm:
97901a344a2SDavid du Colombier if(d->private) {
98001a344a2SDavid du Colombier print("juke platter private pointer set %p\n",
98101a344a2SDavid du Colombier d->private);
98201a344a2SDavid du Colombier panic("jinit: private");
98301a344a2SDavid du Colombier }
98401a344a2SDavid du Colombier d->private = w;
98501a344a2SDavid du Colombier break;
98601a344a2SDavid du Colombier }
98701a344a2SDavid du Colombier }
98801a344a2SDavid du Colombier
98901a344a2SDavid du Colombier Side*
wormi(char * arg)99001a344a2SDavid du Colombier wormi(char *arg)
99101a344a2SDavid du Colombier {
99201a344a2SDavid du Colombier int i, j;
99301a344a2SDavid du Colombier Juke *w;
99401a344a2SDavid du Colombier Side *v;
99501a344a2SDavid du Colombier
99601a344a2SDavid du Colombier i = number(arg, -1, 10) - 1;
99701a344a2SDavid du Colombier w = jukelist;
99801a344a2SDavid du Colombier if(i < 0 || i >= w->nside) {
99901a344a2SDavid du Colombier print("bad unit number %s (%d)\n", arg, i+1);
100001a344a2SDavid du Colombier return 0;
100101a344a2SDavid du Colombier }
100201a344a2SDavid du Colombier j = i;
100301a344a2SDavid du Colombier if(j >= w->nse)
100401a344a2SDavid du Colombier j -= w->nse;
100501a344a2SDavid du Colombier if(j < w->nside) {
100601a344a2SDavid du Colombier v = &w->side[j];
100701a344a2SDavid du Colombier qlock(v);
100801a344a2SDavid du Colombier if(v->status == Sstart) {
100901a344a2SDavid du Colombier if(mmove(w, w->mt0, w->dt0+v->drive, v->elem, v->rot)) {
101001a344a2SDavid du Colombier qunlock(v);
101101a344a2SDavid du Colombier return 0;
101201a344a2SDavid du Colombier }
101301a344a2SDavid du Colombier v->status = Sunload;
101401a344a2SDavid du Colombier }
101501a344a2SDavid du Colombier qunlock(v);
101601a344a2SDavid du Colombier }
101701a344a2SDavid du Colombier j += w->nse;
101801a344a2SDavid du Colombier if(j < w->nside) {
101901a344a2SDavid du Colombier v = &w->side[j];
102001a344a2SDavid du Colombier qlock(v);
102101a344a2SDavid du Colombier if(v->status == Sstart) {
102201a344a2SDavid du Colombier if(mmove(w, w->mt0, w->dt0+v->drive, v->elem, v->rot)) {
102301a344a2SDavid du Colombier qunlock(v);
102401a344a2SDavid du Colombier return 0;
102501a344a2SDavid du Colombier }
102601a344a2SDavid du Colombier v->status = Sunload;
102701a344a2SDavid du Colombier }
102801a344a2SDavid du Colombier qunlock(v);
102901a344a2SDavid du Colombier }
103001a344a2SDavid du Colombier v = &w->side[i];
103101a344a2SDavid du Colombier qlock(v);
103201a344a2SDavid du Colombier return v;
103301a344a2SDavid du Colombier }
103401a344a2SDavid du Colombier
103501a344a2SDavid du Colombier static void
cmd_wormoffline(int argc,char * argv[])103601a344a2SDavid du Colombier cmd_wormoffline(int argc, char *argv[])
103701a344a2SDavid du Colombier {
103801a344a2SDavid du Colombier int u, i;
103901a344a2SDavid du Colombier Juke *w;
104001a344a2SDavid du Colombier
104101a344a2SDavid du Colombier if(argc <= 1) {
104201a344a2SDavid du Colombier print("usage: wormoffline drive\n");
104301a344a2SDavid du Colombier return;
104401a344a2SDavid du Colombier }
104501a344a2SDavid du Colombier u = number(argv[1], -1, 10);
104601a344a2SDavid du Colombier w = jukelist;
104701a344a2SDavid du Colombier if(u < 0 || u >= w->ndrive) {
104801a344a2SDavid du Colombier print("bad drive %s (0<=%d<%d)\n", argv[1], u, w->ndrive);
104901a344a2SDavid du Colombier return;
105001a344a2SDavid du Colombier }
105101a344a2SDavid du Colombier if(w->offline[u])
105201a344a2SDavid du Colombier print("drive %d already offline\n", u);
105301a344a2SDavid du Colombier w->offline[u] = 1;
105401a344a2SDavid du Colombier for(i=0; i<w->ndrive; i++)
105501a344a2SDavid du Colombier if(w->offline[i] == 0)
105601a344a2SDavid du Colombier return;
105701a344a2SDavid du Colombier print("that would take all drives offline\n");
105801a344a2SDavid du Colombier w->offline[u] = 0;
105901a344a2SDavid du Colombier }
106001a344a2SDavid du Colombier
106101a344a2SDavid du Colombier static void
cmd_wormonline(int argc,char * argv[])106201a344a2SDavid du Colombier cmd_wormonline(int argc, char *argv[])
106301a344a2SDavid du Colombier {
106401a344a2SDavid du Colombier int u;
106501a344a2SDavid du Colombier Juke *w;
106601a344a2SDavid du Colombier
106701a344a2SDavid du Colombier if(argc <= 1) {
106801a344a2SDavid du Colombier print("usage: wormonline drive\n");
106901a344a2SDavid du Colombier return;
107001a344a2SDavid du Colombier }
107101a344a2SDavid du Colombier u = number(argv[1], -1, 10);
107201a344a2SDavid du Colombier w = jukelist;
107301a344a2SDavid du Colombier if(u < 0 || u >= w->ndrive) {
107401a344a2SDavid du Colombier print("bad drive %s (0<=%d<%d)\n", argv[1], u, w->ndrive);
107501a344a2SDavid du Colombier return;
107601a344a2SDavid du Colombier }
107701a344a2SDavid du Colombier if(w->offline[u] == 0)
107801a344a2SDavid du Colombier print("drive %d already online\n", u);
107901a344a2SDavid du Colombier w->offline[u] = 0;
108001a344a2SDavid du Colombier }
108101a344a2SDavid du Colombier
108201a344a2SDavid du Colombier void
cmd_wormreset(int,char * [])108301a344a2SDavid du Colombier cmd_wormreset(int, char *[])
108401a344a2SDavid du Colombier {
108501a344a2SDavid du Colombier Juke *w;
108601a344a2SDavid du Colombier
108701a344a2SDavid du Colombier for(w=jukelist; w; w=w->link) {
108801a344a2SDavid du Colombier qlock(w);
108901a344a2SDavid du Colombier positions(w);
109001a344a2SDavid du Colombier qunlock(w);
109101a344a2SDavid du Colombier }
109201a344a2SDavid du Colombier }
109301a344a2SDavid du Colombier
109401a344a2SDavid du Colombier static void
cmd_wormeject(int argc,char * argv[])109501a344a2SDavid du Colombier cmd_wormeject(int argc, char *argv[])
109601a344a2SDavid du Colombier {
109701a344a2SDavid du Colombier Juke *w;
109801a344a2SDavid du Colombier Side *v;
109901a344a2SDavid du Colombier
110001a344a2SDavid du Colombier if(argc <= 1) {
110101a344a2SDavid du Colombier print("usage: wormeject unit\n");
110201a344a2SDavid du Colombier return;
110301a344a2SDavid du Colombier }
110401a344a2SDavid du Colombier v = wormi(argv[1]);
110501a344a2SDavid du Colombier if(v == 0)
110601a344a2SDavid du Colombier return;
110701a344a2SDavid du Colombier w = jukelist;
110801a344a2SDavid du Colombier mmove(w, w->mt0, v->elem, w->ie0, 0);
110901a344a2SDavid du Colombier qunlock(v);
111001a344a2SDavid du Colombier }
111101a344a2SDavid du Colombier
111201a344a2SDavid du Colombier static void
cmd_wormingest(int argc,char * argv[])111301a344a2SDavid du Colombier cmd_wormingest(int argc, char *argv[])
111401a344a2SDavid du Colombier {
111501a344a2SDavid du Colombier Juke *w;
111601a344a2SDavid du Colombier Side *v;
111701a344a2SDavid du Colombier
111801a344a2SDavid du Colombier if(argc <= 1) {
111901a344a2SDavid du Colombier print("usage: wormingest unit\n");
112001a344a2SDavid du Colombier return;
112101a344a2SDavid du Colombier }
112201a344a2SDavid du Colombier v = wormi(argv[1]);
112301a344a2SDavid du Colombier if(v == 0)
112401a344a2SDavid du Colombier return;
112501a344a2SDavid du Colombier w = jukelist;
112601a344a2SDavid du Colombier mmove(w, w->mt0, w->ie0, v->elem, 0);
112701a344a2SDavid du Colombier qunlock(v);
112801a344a2SDavid du Colombier }
112901a344a2SDavid du Colombier
113001a344a2SDavid du Colombier static void
newside(Side * v,int rot,int elem)113101a344a2SDavid du Colombier newside(Side *v, int rot, int elem)
113201a344a2SDavid du Colombier {
113301a344a2SDavid du Colombier qlock(v);
113401a344a2SDavid du Colombier qunlock(v);
113501a344a2SDavid du Colombier // v->name = "shelf";
113601a344a2SDavid du Colombier v->elem = elem;
113701a344a2SDavid du Colombier v->rot = rot;
113801a344a2SDavid du Colombier v->status = Sempty;
113901a344a2SDavid du Colombier v->time = toytime();
114001a344a2SDavid du Colombier }
114101a344a2SDavid du Colombier
114201a344a2SDavid du Colombier /*
114301a344a2SDavid du Colombier * query jukebox robotics for geometry;
114401a344a2SDavid du Colombier * argument is the wren dev of the changer.
114501a344a2SDavid du Colombier * result is actually Juke*, but that type is only known in this file.
114601a344a2SDavid du Colombier */
114701a344a2SDavid du Colombier void *
querychanger(Device * xdev)114801a344a2SDavid du Colombier querychanger(Device *xdev)
114901a344a2SDavid du Colombier {
115001a344a2SDavid du Colombier Juke *w;
115101a344a2SDavid du Colombier Side *v;
115201a344a2SDavid du Colombier int i;
115301a344a2SDavid du Colombier
115401a344a2SDavid du Colombier if (xdev == nil)
115501a344a2SDavid du Colombier panic("querychanger: nil Device");
115601a344a2SDavid du Colombier if(xdev->type != Devwren) {
115701a344a2SDavid du Colombier print("juke changer not wren %Z\n", xdev);
115801a344a2SDavid du Colombier goto bad;
115901a344a2SDavid du Colombier }
116001a344a2SDavid du Colombier for(w=jukelist; w; w=w->link)
116101a344a2SDavid du Colombier if(xdev == w->juke)
116201a344a2SDavid du Colombier return w;
116301a344a2SDavid du Colombier
116401a344a2SDavid du Colombier /*
116501a344a2SDavid du Colombier * allocate a juke structure
116601a344a2SDavid du Colombier * no locking problems.
116701a344a2SDavid du Colombier */
116801a344a2SDavid du Colombier w = malloc(sizeof(Juke));
116901a344a2SDavid du Colombier w->magic = Jukemagic;
117001a344a2SDavid du Colombier w->isfixedsize = FIXEDSIZE;
117101a344a2SDavid du Colombier w->link = jukelist;
117201a344a2SDavid du Colombier jukelist = w;
117301a344a2SDavid du Colombier
117401a344a2SDavid du Colombier print("alloc juke %Z\n", xdev);
117501a344a2SDavid du Colombier qlock(w);
117601a344a2SDavid du Colombier qunlock(w);
117701a344a2SDavid du Colombier // w->name = "juke";
117801a344a2SDavid du Colombier w->juke = xdev;
117901a344a2SDavid du Colombier w->robotdir = sdof(xdev);
118001a344a2SDavid du Colombier w->robot = openscsi(w->robotdir);
118101a344a2SDavid du Colombier if (w->robot == nil)
118201a344a2SDavid du Colombier panic("can't openscsi(%s): %r", w->robotdir);
118301a344a2SDavid du Colombier newscsi(xdev, w->robot);
118401a344a2SDavid du Colombier geometry(w);
118501a344a2SDavid du Colombier
118601a344a2SDavid du Colombier /*
118701a344a2SDavid du Colombier * pick up each side
118801a344a2SDavid du Colombier */
118901a344a2SDavid du Colombier w->nside = w->nse;
119001a344a2SDavid du Colombier if(w->rot)
119101a344a2SDavid du Colombier w->nside += w->nside;
119201a344a2SDavid du Colombier if(w->nside > MAXSIDE) {
119301a344a2SDavid du Colombier print("too many sides: %d max %d\n", w->nside, MAXSIDE);
119401a344a2SDavid du Colombier goto bad;
119501a344a2SDavid du Colombier }
119601a344a2SDavid du Colombier for(i=0; i < w->nse; i++) {
119701a344a2SDavid du Colombier v = &w->side[i];
119801a344a2SDavid du Colombier newside(v, 0, w->se0 + i);
119901a344a2SDavid du Colombier if(w->rot)
120001a344a2SDavid du Colombier newside(v + w->nse, 1, w->se0 + i);
120101a344a2SDavid du Colombier }
120201a344a2SDavid du Colombier positions(w);
120301a344a2SDavid du Colombier
120401a344a2SDavid du Colombier w->ndrive = w->ndt;
120501a344a2SDavid du Colombier if(w->ndrive > MAXDRIVE) {
120601a344a2SDavid du Colombier print("ndrives truncated to %d\n", MAXDRIVE);
120701a344a2SDavid du Colombier w->ndrive = MAXDRIVE;
120801a344a2SDavid du Colombier }
120901a344a2SDavid du Colombier
121001a344a2SDavid du Colombier /*
121101a344a2SDavid du Colombier * pick up each drive
121201a344a2SDavid du Colombier */
121301a344a2SDavid du Colombier for(i=0; i<w->ndrive; i++)
121401a344a2SDavid du Colombier w->drive[i] = devnone;
121501a344a2SDavid du Colombier return w;
121601a344a2SDavid du Colombier bad:
121701a344a2SDavid du Colombier panic("querychanger: %Z", xdev);
121801a344a2SDavid du Colombier return nil;
121901a344a2SDavid du Colombier }
122001a344a2SDavid du Colombier
122101a344a2SDavid du Colombier void
jukeinit(Device * d)122201a344a2SDavid du Colombier jukeinit(Device *d)
122301a344a2SDavid du Colombier {
122401a344a2SDavid du Colombier Juke *w;
122501a344a2SDavid du Colombier Device *xdev;
122601a344a2SDavid du Colombier int i;
122701a344a2SDavid du Colombier static int beenhere = 0;
122801a344a2SDavid du Colombier
122901a344a2SDavid du Colombier /* j(w<changer>w<station0>...)(r<platters>) */
123001a344a2SDavid du Colombier if (d == nil)
123101a344a2SDavid du Colombier panic("jukeinit: nil Device");
123201a344a2SDavid du Colombier xdev = d->j.j;
123301a344a2SDavid du Colombier if(xdev == nil || xdev->type != Devmcat) {
123401a344a2SDavid du Colombier print("juke union not mcat\n");
123501a344a2SDavid du Colombier goto bad;
123601a344a2SDavid du Colombier }
123701a344a2SDavid du Colombier
123801a344a2SDavid du Colombier /*
123901a344a2SDavid du Colombier * pick up the changer device
124001a344a2SDavid du Colombier */
124101a344a2SDavid du Colombier xdev = xdev->cat.first;
124201a344a2SDavid du Colombier w = querychanger(xdev);
124301a344a2SDavid du Colombier
124401a344a2SDavid du Colombier if (!beenhere) {
124501a344a2SDavid du Colombier beenhere = 1;
124601a344a2SDavid du Colombier cmd_install("wormreset",
124701a344a2SDavid du Colombier "-- put drives back where jukebox thinks they belong",
124801a344a2SDavid du Colombier cmd_wormreset);
124901a344a2SDavid du Colombier cmd_install("wormeject", "unit -- shelf to outside",
125001a344a2SDavid du Colombier cmd_wormeject);
125101a344a2SDavid du Colombier cmd_install("wormingest", "unit -- outside to shelf",
125201a344a2SDavid du Colombier cmd_wormingest);
125301a344a2SDavid du Colombier cmd_install("wormoffline", "unit -- disable drive",
125401a344a2SDavid du Colombier cmd_wormoffline);
125501a344a2SDavid du Colombier cmd_install("wormonline", "unit -- enable drive",
125601a344a2SDavid du Colombier cmd_wormonline);
125701a344a2SDavid du Colombier }
125801a344a2SDavid du Colombier
125901a344a2SDavid du Colombier /* walk through the worm drives */
126001a344a2SDavid du Colombier i = 0;
126101a344a2SDavid du Colombier while(xdev = xdev->link) {
126201a344a2SDavid du Colombier if(xdev->type != Devwren) {
126301a344a2SDavid du Colombier print("drive not devwren: %Z\n", xdev);
126401a344a2SDavid du Colombier goto bad;
126501a344a2SDavid du Colombier }
126601a344a2SDavid du Colombier if(w->drive[i]->type != Devnone &&
126701a344a2SDavid du Colombier xdev != w->drive[i]) {
126801a344a2SDavid du Colombier print("double init drive %d %Z %Z\n",
126901a344a2SDavid du Colombier i, w->drive[i], xdev);
127001a344a2SDavid du Colombier goto bad;
127101a344a2SDavid du Colombier }
127201a344a2SDavid du Colombier if(i >= w->ndrive) {
127301a344a2SDavid du Colombier print("too many drives %Z\n", xdev);
127401a344a2SDavid du Colombier goto bad;
127501a344a2SDavid du Colombier }
127601a344a2SDavid du Colombier w->drive[i++] = xdev;
127701a344a2SDavid du Colombier }
127801a344a2SDavid du Colombier
127901a344a2SDavid du Colombier if(i <= 0) {
128001a344a2SDavid du Colombier print("no drives\n");
128101a344a2SDavid du Colombier goto bad;
128201a344a2SDavid du Colombier }
128301a344a2SDavid du Colombier
128401a344a2SDavid du Colombier /*
128501a344a2SDavid du Colombier * put w pointer in each platter
128601a344a2SDavid du Colombier */
128701a344a2SDavid du Colombier d->private = w;
128801a344a2SDavid du Colombier jinit(w, d->j.m, 0);
128901a344a2SDavid du Colombier w->probeok = 1;
129001a344a2SDavid du Colombier return;
129101a344a2SDavid du Colombier
129201a344a2SDavid du Colombier bad:
129301a344a2SDavid du Colombier panic("juke init");
129401a344a2SDavid du Colombier }
129501a344a2SDavid du Colombier
129601a344a2SDavid du Colombier /*
129701a344a2SDavid du Colombier * called periodically
129801a344a2SDavid du Colombier */
129901a344a2SDavid du Colombier void
wormprobe(void)130001a344a2SDavid du Colombier wormprobe(void)
130101a344a2SDavid du Colombier {
130201a344a2SDavid du Colombier int i, drive;
130301a344a2SDavid du Colombier Timet t;
130401a344a2SDavid du Colombier Side *v;
130501a344a2SDavid du Colombier Juke *w;
130601a344a2SDavid du Colombier
130701a344a2SDavid du Colombier t = toytime() - TWORM;
130801a344a2SDavid du Colombier for(w=jukelist; w; w=w->link) {
130901a344a2SDavid du Colombier if(w->probeok == 0 || !canqlock(w))
131001a344a2SDavid du Colombier continue;
131101a344a2SDavid du Colombier for(i=0; i<w->nside; i++) {
131201a344a2SDavid du Colombier v = &w->side[i];
131301a344a2SDavid du Colombier if(!canqlock(v))
131401a344a2SDavid du Colombier continue;
131501a344a2SDavid du Colombier if(v->status == Sstart && t > v->time) {
131601a344a2SDavid du Colombier drive = v->drive;
131701a344a2SDavid du Colombier print("\ttime r%ld drive %Z\n",
131801a344a2SDavid du Colombier v-w->side, w->drive[drive]);
131901a344a2SDavid du Colombier mmove(w, w->mt0, w->dt0+drive, v->elem, v->rot);
132001a344a2SDavid du Colombier v->status = Sunload;
132101a344a2SDavid du Colombier }
132201a344a2SDavid du Colombier qunlock(v);
132301a344a2SDavid du Colombier }
132401a344a2SDavid du Colombier qunlock(w);
132501a344a2SDavid du Colombier }
132601a344a2SDavid du Colombier }
1327