123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- /*
- * drive HP optical-disc jukeboxes (e.g. HP 1200EX).
- * used to issue SCSI commands directly to the host adapter;
- * now (via scsi.c) it issues them via scsi(2) using
- * /dev/sdXX/raw to run the robotics, and uses normal i/o
- * on /dev/sdXX/data to run the drives.
- */
- #include "all.h"
- #include "io.h"
- enum {
- SCSInone = SCSIread,
- MAXDRIVE = 10,
- MAXSIDE = 500, /* max. disc sides */
- TWORM = MINUTE(10),
- THYSTER = SECOND(10),
- Sectorsz = 512, /* usual disk sector size */
- Jukemagic = 0xbabfece2,
- };
- typedef struct Side Side;
- struct Side
- {
- QLock; /* protects loading/unloading */
- int elem; /* element number */
- int drive; /* if loaded, where */
- uchar status; /* Sunload, etc */
- uchar rot; /* if backside */
- int ord; /* ordinal number for labeling */
- Timet time; /* time since last access, to unspin */
- Timet stime; /* time since last spinup, for hysteresis */
- long nblock; /* number of native blocks */
- long block; /* bytes per native block */
- long mult; /* multiplier to get plan9 blocks */
- long max; /* max size in plan9 blocks */
- };
- typedef struct Juke Juke;
- struct Juke
- {
- QLock; /* protects drive mechanism */
- Side side[MAXSIDE];
- int nside; /* # of storage elements (*2 if rev) */
- int ndrive; /* # of transfer elements */
- Device* juke; /* devworm of changer */
- Device* drive[MAXDRIVE]; /* devworm for i/o */
- uchar offline[MAXDRIVE]; /* drives removed from service */
- int isfixedsize; /* flag: one size fits all? */
- long fixedsize; /* the one size that fits all */
- int probeok; /* wait for init to probe */
- Scsi* robot; /* scsi(2) interface to robotics */
- char* robotdir; /* /dev/sdXX name */
- /*
- * geometry returned by mode sense.
- * a *0 number (such as mt0) is the `element number' of the
- * first element of that type (e.g., mt, or motor transport).
- * an n* number is the quantity of them.
- */
- int mt0, nmt; /* motor transports (robot pickers) */
- int se0, nse; /* storage elements (discs, slots) */
- int ie0, nie; /* interchange elements (mailbox slots) */
- int dt0, ndt; /* drives (data transfer?) */
- int rot; /* if true, discs are double-sided */
- ulong magic;
- Juke* link;
- };
- static Juke* jukelist;
- enum
- {
- Sempty = 0, /* does not exist */
- Sunload, /* on the shelf */
- Sstart, /* loaded and spinning */
- };
- static int bestdrive(Juke*, int);
- static void element(Juke*, int);
- static int mmove(Juke*, int, int, int, int);
- static void shelves(void);
- static int waitready(Juke *, Device*);
- static int wormsense(Device*);
- static Side* wormunit(Device*);
- /* create a new label and try to write it */
- static void
- newlabel(Device *d, Off labelblk, char *labelbuf, unsigned vord)
- {
- Label *label = (Label *)labelbuf;
- memset(labelbuf, 0, RBUFSIZE);
- label->magic = Labmagic;
- label->ord = vord;
- strncpy(label->service, service, sizeof label->service);
- if (!okay("write new label"))
- print("NOT writing new label\n");
- else if (wormwrite(d, labelblk, labelbuf))
- /* wormwrite will have complained in detail */
- print("can't write new label on side %d\n", vord);
- else
- print("wrote new label on side %d\n", vord);
- }
- /* check for label in last block. call with v qlocked. */
- Side*
- wormlabel(Device *d, Side *v)
- {
- int vord;
- Off labelblk = v->max - 1; /* last block */
- char labelbuf[RBUFSIZE];
- Label *label = (Label *)labelbuf;
- Juke *w = d->private;
- /* wormread calls wormunit, which locks v */
- vord = v->ord;
- qunlock(v);
- memset(label, 0, sizeof *label);
- if (wormread(d, labelblk, labelbuf)) {
- /*
- * wormread will have complained in detail about the error;
- * no need to repeat most of that detail.
- * probably an unwritten WORM-disc label; write a new one.
- */
- print("error reading label block of side %d\n", vord);
- newlabel(d, labelblk, labelbuf, vord);
- } else if (label->magic != Labmagic) {
- swab8(&label->magic);
- if (label->magic == Labmagic) {
- print(
- "side %d's label magic byte-swapped; filsys should be configured with xD",
- vord);
- swab2(&label->ord);
- /* could look for Devswab in Juke's filsys */
- } else {
- /*
- * magic # is wrong in both byte orders, thus
- * probably the label is empty on RW media,
- * so create a new one and try to write it.
- */
- print("bad magic number in label of side %d\n", vord);
- newlabel(d, labelblk, labelbuf, vord);
- }
- }
- qlock(v);
- if (v->ord != vord)
- panic("wormlabel: side %d switched ordinal to %d underfoot",
- vord, v->ord);
- if (label->ord != vord) {
- print(
- "labelled worm side %Z has wrong ordinal in label (%d, want %d)",
- d, label->ord, vord);
- qunlock(v);
- cmd_wormreset(0, nil); /* put discs away */
- panic("wrong ordinal in label");
- }
- print("label %Z ordinal %d\n", d, v->ord);
- qunlock(v);
- /*
- * wormunit should return without calling us again,
- * since v is now known.
- */
- if (w != d->private)
- panic("wormlabel: w != %Z->private", d);
- return wormunit(d);
- }
- /*
- * mounts and spins up the device
- * locks the structure
- */
- static Side*
- wormunit(Device *d) /* d is l0 or r2 (e.g.) */
- {
- int p, drive;
- Device *dr; /* w0 or w1.2.0 (e.g.) */
- Side *v;
- Juke *w;
- Dir *dir;
- w = d->private;
- if (w == nil)
- panic("wormunit %Z nil juke", d);
- if (w->magic != Jukemagic)
- panic("bad magic in Juke for %Z", d);
- p = d->wren.targ;
- if(p < 0 || w && p >= w->nside) {
- panic("wormunit: target %d out of range for %Z", p, d);
- return 0;
- }
- /*
- * if disk is unloaded, must load it
- * into next (circular) logical unit
- */
- v = &w->side[p];
- qlock(v);
- if(v->status == Sunload) {
- for(;;) {
- qlock(w);
- drive = bestdrive(w, p);
- if(drive >= 0)
- break;
- qunlock(w);
- delay(100);
- }
- print("\tload r%ld drive %Z\n", v-w->side, w->drive[drive]);
- if(mmove(w, w->mt0, v->elem, w->dt0+drive, v->rot)) {
- qunlock(w);
- goto sbad;
- }
- v->drive = drive;
- v->status = Sstart;
- v->stime = toytime();
- qunlock(w);
- dr = w->drive[drive];
- if (!waitready(w, dr))
- goto sbad;
- v->stime = toytime();
- } else
- dr = w->drive[v->drive];
- if(v->status != Sstart) {
- if(v->status == Sempty)
- print("worm: unit empty %Z\n", d);
- else
- print("worm: not started %Z\n", d);
- goto sbad;
- }
- v->time = toytime();
- if(v->block) /* side is known already */
- return v;
- /*
- * load and record information about side
- */
- if (dr->wren.file)
- dr->wren.sddata = dataof(dr->wren.file);
- else {
- if (dr->wren.sddir == nil) {
- if (dr->type == Devwren)
- dr->wren.sddir = sdof(dr);
- if (dr->wren.sddir == nil)
- panic("wormunit: %Z for %Z not a wren", dr, d);
- }
- dr->wren.sddata = smprint("%s/data", dr->wren.sddir);
- }
- if (dr->wren.fd == 0)
- dr->wren.fd = open(dr->wren.sddata, ORDWR);
- if (dr->wren.fd < 0) {
- print("wormunit: can't open %s for %Z: %r\n", dr->wren.sddata, d);
- goto sbad;
- }
- v->block = inqsize(dr->wren.sddata);
- if(v->block <= 0) {
- print("\twormunit %Z block size %ld, setting to %d\n",
- d, v->block, Sectorsz);
- v->block = Sectorsz;
- }
- dir = dirfstat(dr->wren.fd);
- v->nblock = dir->length / v->block;
- free(dir);
- v->mult = (RBUFSIZE + v->block - 1) / v->block;
- v->max = (v->nblock + 1) / v->mult;
- print("\tworm %Z: drive %Z (juke drive %d)\n",
- d, w->drive[v->drive], v->drive);
- print("\t\t%,ld %ld-byte sectors, ", v->nblock, v->block);
- print("%,ld %d-byte blocks\n", v->max, RBUFSIZE);
- print("\t\t%ld multiplier\n", v->mult);
- if(d->type == Devlworm)
- return wormlabel(d, v);
- else
- return v;
- sbad:
- qunlock(v);
- return 0;
- }
- /* wait 10s for optical drive to spin up */
- static int
- waitready(Juke *w, Device *d)
- {
- int p, e, rv;
- char *datanm;
- if (w->magic != Jukemagic)
- panic("waitready: bad magic in Juke (d->private) for %Z", d);
- p = d->wren.targ;
- if(p < 0 || p >= w->nside) {
- print("waitready: target %d out of range for %Z\n", p, d);
- return 0;
- }
- if (d->type == Devwren && d->wren.file)
- datanm = strdup(d->wren.file);
- else {
- if (d->wren.sddir)
- free(d->wren.sddir);
- if (d->type == Devwren)
- d->wren.sddir = sdof(d);
- if (d->wren.sddir == nil)
- panic("waitready: d->wren.sddir not set for %Z", d);
- datanm = smprint("%s/data", d->wren.sddir);
- }
- rv = 0;
- for(e=0; e < 100; e++) {
- if (e == 10)
- print("waitready: waiting for %s to exist\n", datanm); // DEBUG
- if (access(datanm, AEXIST) >= 0) {
- rv = 1;
- break;
- }
- delay(200);
- }
- if (rv == 0)
- print("waitready: %s for %Z didn't come ready\n", datanm, d);
- free(datanm);
- return rv;
- }
- static int
- bestdrive(Juke *w, int side)
- {
- Side *v, *bv[MAXDRIVE];
- int i, e, drive;
- Timet t, t0;
- loop:
- /* build table of what platters on what drives */
- for(i=0; i<w->ndt; i++)
- bv[i] = 0;
- v = &w->side[0];
- for(i=0; i < w->nside; i++, v++)
- if(v->status == Sstart) {
- drive = v->drive;
- if(drive >= 0 && drive < w->ndt)
- bv[drive] = v;
- }
- /*
- * find oldest drive, but must be
- * at least THYSTER old.
- */
- e = w->side[side].elem;
- t0 = toytime() - THYSTER;
- t = t0;
- drive = -1;
- for(i=0; i<w->ndt; i++) {
- v = bv[i];
- if(v == 0) { /* 2nd priority: empty drive */
- if(w->offline[i])
- continue;
- if(w->drive[i] != devnone) {
- drive = i;
- t = 0;
- }
- continue;
- }
- if(v->elem == e) { /* 1st priority: other side */
- drive = -1;
- if(v->stime < t0)
- drive = i;
- break;
- }
- if(v->stime < t) { /* 3rd priority: by time */
- drive = i;
- t = v->stime;
- }
- }
- if(drive >= 0) {
- v = bv[drive];
- if(v) {
- qlock(v);
- if(v->status != Sstart) {
- qunlock(v);
- goto loop;
- }
- print("\tunload r%ld drive %Z\n",
- v-w->side, w->drive[drive]);
- if(mmove(w, w->mt0, w->dt0+drive, v->elem, v->rot)) {
- qunlock(v);
- goto loop;
- }
- v->status = Sunload;
- qunlock(v);
- }
- }
- return drive;
- }
- Devsize
- wormsize(Device *d)
- {
- Side *v;
- Juke *w;
- Devsize size;
- w = d->private;
- if (w->magic != Jukemagic)
- print("wormsize: bad magic in Juke (d->private) for %Z\n", d);
- if(w->isfixedsize && w->fixedsize != 0)
- size = w->fixedsize; /* fixed size is now known */
- else {
- if (w != d->private)
- panic("wormsize: w != %Z->private", d);
- v = wormunit(d);
- if(v == nil)
- return 0;
- size = v->max;
- qunlock(v);
- /*
- * set fixed size for whole Juke from
- * size of first disc examined.
- */
- if(w->isfixedsize)
- w->fixedsize = size;
- }
- if(d->type == Devlworm)
- return size-1; /* lie: last block is for label */
- return size;
- }
- /*
- * return a Devjuke or an mcat (normally of sides) from within d (or nil).
- * if it's an mcat, the caller must walk it.
- */
- static Device *
- devtojuke(Device *d, Device *top)
- {
- while (d != nil)
- switch(d->type) {
- default:
- print("devtojuke: type of device %Z of %Z unknown\n",
- d, top);
- return nil;
- case Devjuke:
- /* jackpot! d->private is a (Juke *) with nside, &c. */
- /* FALL THROUGH */
- case Devmcat:
- case Devmlev:
- case Devmirr:
- /* squint hard & call an mlev or a mirr an mcat */
- return d;
- case Devworm:
- case Devlworm:
- /*
- * d->private is a (Juke *) with nside, etc.,
- * but we're not supposed to get here.
- */
- print("devtojuke: (l)worm %Z of %Z encountered\n",
- d, top);
- /* FALL THROUGH */
- case Devwren:
- return nil;
- case Devcw:
- d = d->cw.w; /* usually juke */
- break;
- case Devro:
- d = d->ro.parent; /* cw */
- break;
- case Devfworm:
- d = d->fw.fw;
- break;
- case Devpart:
- d = d->part.d;
- break;
- case Devswab:
- d = d->swab.d;
- break;
- }
- return d;
- }
- static int
- devisside(Device *d)
- {
- return d->type == Devworm || d->type == Devlworm;
- }
- static Device *
- findside(Device *juke, int side, Device *top)
- {
- int i = 0;
- Device *mcat = juke->j.m, *x;
- Juke *w = juke->private;
- for (x = mcat->cat.first; x != nil; x = x->link) {
- if (!devisside(x)) {
- print("wormsizeside: %Z of %Z of %Z type not (l)worm\n",
- x, mcat, top);
- return nil;
- }
- i = x->wren.targ;
- if (i < 0 || i >= w->nside)
- panic("wormsizeside: side %d in %Z out of range",
- i, mcat);
- if (i == side)
- break;
- }
- if (x == nil)
- return nil;
- if (w->side[i].time == 0) {
- print("wormsizeside: side %d not in jukebox %Z\n", i, juke);
- return nil;
- }
- return x;
- }
- typedef struct {
- int sleft; /* sides still to visit to reach desired side */
- int starget; /* side of topdev we want */
- Device *topdev;
- int sawjuke; /* passed by a jukebox */
- int sized; /* flag: asked wormsize for size of starget */
- } Visit;
- /*
- * walk the Device tree from d looking for Devjukes, counting sides.
- * the main complication is mcats and the like with Devjukes in them.
- * use Devjuke's d->private as Juke* and see sides.
- */
- static Off
- visitsides(Device *d, Device *parentj, Visit *vp)
- {
- Off size = 0;
- Device *x;
- Juke *w;
- /*
- * find the first juke or mcat.
- * d==nil means we couldn't find one; typically harmless, due to a
- * mirror of dissimilar devices.
- */
- d = devtojuke(d, vp->topdev);
- if (d == nil || vp->sleft < 0)
- return 0;
- if (d->type == Devjuke) { /* jackpot! d->private is a (Juke *) */
- vp->sawjuke = 1;
- w = d->private;
- /*
- * if there aren't enough sides in this jukebox to reach
- * the desired one, subtract these sides and pass.
- */
- if (vp->sleft >= w->nside) {
- vp->sleft -= w->nside;
- return 0;
- }
- /* else this is the right juke, paw through mcat of sides */
- return visitsides(d->j.m, d, vp);
- }
- /*
- * d will usually be an mcat of sides, but it could be an mcat of
- * jukes, for example. in that case, we need to walk the mcat,
- * recursing as needed, until we find the right juke, then stop at
- * the right side within its mcat of sides, by comparing side
- * numbers, not just by counting (to allow for unused slots).
- */
- x = d->cat.first;
- if (x == nil) {
- print("visitsides: %Z of %Z: empty mcat\n", d, vp->topdev);
- return 0;
- }
- if (!devisside(x)) {
- for (; x != nil && !vp->sized; x = x->link)
- size = visitsides(x, parentj, vp);
- return size;
- }
- /* the side we want is in this jukebox, thus this mcat (d) */
- if (parentj == nil) {
- print("visitsides: no parent juke for sides mcat %Z\n", d);
- vp->sleft = -1;
- return 0;
- }
- if (d != parentj->j.m)
- panic("visitsides: mcat mismatch %Z vs %Z", d, parentj->j.m);
- x = findside(parentj, vp->sleft, vp->topdev);
- if (x == nil) {
- vp->sleft = -1;
- return 0;
- }
- /* we've turned vp->starget into the right Device* */
- vp->sleft = 0;
- vp->sized = 1;
- return wormsize(x);
- }
- /*
- * d must be, or be within, a filesystem config that also contains
- * the jukebox that `side' resides on.
- * d is normally a Devcw, but could be Devwren, Devide, Devpart, Devfworm,
- * etc. if called from chk.c Ctouch code. Note too that the worm part of
- * the Devcw might be other than a Devjuke.
- */
- Devsize
- wormsizeside(Device *d, int side)
- {
- Devsize size;
- Visit visit;
- memset(&visit, 0, sizeof visit);
- visit.starget = visit.sleft = side;
- visit.topdev = d;
- size = visitsides(d, nil, &visit);
- if (visit.sawjuke && (visit.sleft != 0 || !visit.sized)) {
- print("wormsizeside: fewer than %d sides in %Z\n", side, d);
- return 0;
- }
- return size;
- }
- /*
- * returns starts (in blocks) of side #side and #(side+1) of dev in *stp.
- * dev should be a Devcw.
- */
- void
- wormsidestarts(Device *dev, int side, Sidestarts *stp)
- {
- int s;
- Devsize dstart;
- for (dstart = s = 0; s < side; s++)
- dstart += wormsizeside(dev, s);
- stp->sstart = dstart;
- stp->s1start = dstart + wormsizeside(dev, side);
- }
- int
- wormread(Device *d, Off b, void *c)
- {
- int r = 0;
- int32_t max;
- char name[128];
- Side *v = wormunit(d);
- Juke *w = d->private;
- Device *dr;
- if (v == nil)
- panic("wormread: nil wormunit(%Z)", d);
- dr = w->drive[v->drive];
- if (dr->wren.fd < 0)
- panic("wormread: unopened fd for %Z", d);
- max = (d->type == Devlworm? v->max + 1: v->max);
- if(b >= max) {
- print("wormread: block out of range %Z(%lld)\n", d, (Wideoff)b);
- r = 0x071;
- } else if (pread(dr->wren.fd, c, RBUFSIZE, (int64_t)b*RBUFSIZE) != RBUFSIZE) {
- fd2path(dr->wren.fd, name, sizeof name);
- print("wormread: error on %Z(%lld) on %s in %s: %r\n",
- d, (Wideoff)b, name, dr->wren.sddir);
- cons.nwormre++;
- r = 1;
- }
- qunlock(v);
- return r;
- }
- int
- wormwrite(Device *d, Off b, void *c)
- {
- int r = 0;
- int32_t max;
- char name[128];
- Side *v = wormunit(d);
- Juke *w = d->private;
- Device *dr;
- if (v == nil)
- panic("wormwrite: nil wormunit(%Z)", d);
- dr = w->drive[v->drive];
- if (dr->wren.fd < 0)
- panic("wormwrite: unopened fd for %Z", d);
- max = (d->type == Devlworm? v->max + 1: v->max);
- if(b >= max) {
- print("wormwrite: block out of range %Z(%lld)\n",
- d, (Wideoff)b);
- r = 0x071;
- } else if (pwrite(dr->wren.fd, c, RBUFSIZE, (int64_t)b*RBUFSIZE) != RBUFSIZE) {
- fd2path(dr->wren.fd, name, sizeof name);
- print("wormwrwite: error on %Z(%lld) on %s in %s: %r\n",
- d, (Wideoff)b, name, dr->wren.sddir);
- cons.nwormwe++;
- r = 1;
- }
- qunlock(v);
- return r;
- }
- static int
- mmove(Juke *w, int trans, int from, int to, int rot)
- {
- int s;
- uint8_t cmd[12], buf[4];
- static int recur = 0;
- memset(cmd, 0, sizeof cmd);
- cmd[0] = 0xa5; /* move medium */
- cmd[2] = trans>>8;
- cmd[3] = trans;
- cmd[4] = from>>8;
- cmd[5] = from;
- cmd[6] = to>>8;
- cmd[7] = to;
- if(rot)
- cmd[10] = 1;
- s = scsiio(w->juke, SCSInone, cmd, sizeof cmd, buf, 0); /* mmove */
- if(s) {
- print("scsio status #%x\n", s);
- print("move medium t=%d fr=%d to=%d rot=%d\n",
- trans, from, to, rot);
- // panic("mmove");
- if(recur == 0) {
- recur = 1;
- print("element from=%d\n", from);
- element(w, from);
- print("element to=%d\n", to);
- element(w, to);
- print("element trans=%d\n", trans);
- element(w, trans);
- recur = 0;
- }
- return 1;
- }
- return 0;
- }
- static void
- geometry(Juke *w)
- {
- int s;
- uint8_t cmd[6], buf[4+20];
- memset(cmd, 0, sizeof cmd);
- memset(buf, 0, sizeof buf);
- cmd[0] = 0x1a; /* mode sense */
- cmd[2] = 0x1d; /* element address assignment */
- cmd[4] = sizeof buf; /* allocation length */
- s = scsiio(w->juke, SCSIread, cmd, sizeof cmd, buf, sizeof buf); /* mode sense elem addrs */
- if(s)
- panic("geometry #%x", s);
- w->mt0 = (buf[4+2]<<8) | buf[4+3];
- w->nmt = (buf[4+4]<<8) | buf[4+5];
- w->se0 = (buf[4+6]<<8) | buf[4+7];
- w->nse = (buf[4+8]<<8) | buf[4+9];
- w->ie0 = (buf[4+10]<<8) | buf[4+11];
- w->nie = (buf[4+12]<<8) | buf[4+13];
- w->dt0 = (buf[4+14]<<8) | buf[4+15];
- w->ndt = (buf[4+16]<<8) | buf[4+17];
- memset(cmd, 0, 6);
- memset(buf, 0, sizeof buf);
- cmd[0] = 0x1a; /* mode sense */
- cmd[2] = 0x1e; /* transport geometry */
- cmd[4] = sizeof buf; /* allocation length */
- s = scsiio(w->juke, SCSIread, cmd, sizeof cmd, buf, sizeof buf); /* mode sense geometry */
- if(s)
- panic("geometry #%x", s);
- w->rot = buf[4+2] & 1;
- print("\tmt %d %d\n", w->mt0, w->nmt);
- print("\tse %d %d\n", w->se0, w->nse);
- print("\tie %d %d\n", w->ie0, w->nie);
- print("\tdt %d %d\n", w->dt0, w->ndt);
- print("\trot %d\n", w->rot);
- prflush();
- }
- /*
- * read element e's status from jukebox w, move any disc in drive back to its
- * slot, and update and print software status.
- */
- static void
- element(Juke *w, int e)
- {
- uint8_t cmd[12], buf[8+8+88];
- int s, t;
- memset(cmd, 0, sizeof cmd);
- memset(buf, 0, sizeof buf);
- cmd[0] = 0xb8; /* read element status */
- cmd[2] = e>>8; /* starting element */
- cmd[3] = e;
- cmd[5] = 1; /* number of elements */
- cmd[9] = sizeof buf; /* allocation length */
- s = scsiio(w->juke, SCSIread, cmd, sizeof cmd, buf, sizeof buf); /* read elem sts */
- if(s) {
- print("scsiio #%x\n", s);
- goto bad;
- }
- s = (buf[0]<<8) | buf[1];
- if(s != e) {
- print("element = %d\n", s);
- goto bad;
- }
- if(buf[3] != 1) {
- print("number reported = %d\n", buf[3]);
- goto bad;
- }
- s = (buf[8+8+0]<<8) | buf[8+8+1];
- if(s != e) {
- print("element1 = %d\n", s);
- goto bad;
- }
- switch(buf[8+0]) { /* element type */
- default:
- print("unknown element %d: %d\n", e, buf[8+0]);
- goto bad;
- case 1: /* transport */
- s = e - w->mt0;
- if(s < 0 || s >= w->nmt)
- goto bad;
- if(buf[8+8+2] & 1)
- print("transport %d full %d.%d\n", s,
- (buf[8+8+10]<<8) | buf[8+8+11],
- (buf[8+8+9]>>6) & 1);
- break;
- case 2: /* storage */
- s = e - w->se0;
- if(s < 0 || s >= w->nse)
- goto bad;
- w->side[s].status = Sempty;
- if(buf[8+8+2] & 1)
- w->side[s].status = Sunload;
- if(w->rot)
- w->side[w->nse+s].status = w->side[s].status;
- break;
- case 3: /* import/export */
- s = e - w->ie0;
- if(s < 0 || s >= w->nie)
- goto bad;
- print("import/export %d #%.2x %d.%d\n", s,
- buf[8+8+2],
- (buf[8+8+10]<<8) | buf[8+8+11],
- (buf[8+8+9]>>6) & 1);
- break;
- case 4: /* data transfer */
- s = e - w->dt0;
- if(s < 0 || s >= w->ndt)
- goto bad;
- print("data transfer %d #%.2x %d.%d\n", s,
- buf[8+8+2],
- (buf[8+8+10]<<8) | buf[8+8+11],
- (buf[8+8+9]>>6) & 1);
- if(buf[8+8+2] & 1) {
- t = ((buf[8+8+10]<<8) | buf[8+8+11]) - w->se0;
- if (t < 0 || t >= w->nse || t >= MAXSIDE ||
- s >= MAXDRIVE) {
- print(
- "element: juke %Z lies; claims side %d is in drive %d\n",
- w->juke, t, s); /* lying sack of ... */
- /*
- * at minimum, we've avoided corrupting our
- * data structures. if we know that numbers
- * like w->nside are valid here, we could use
- * them in more stringent tests.
- * perhaps should whack the jukebox upside the
- * head here to knock some sense into it.
- */
- goto bad;
- }
- print("r%d in drive %d\n", t, s);
- if(mmove(w, w->mt0, w->dt0+s, w->se0+t,
- (buf[8+8+9]>>6) & 1)) {
- print("mmove initial unload\n");
- goto bad;
- }
- w->side[t].status = Sunload;
- if(w->rot)
- w->side[w->nse+t].status = Sunload;
- }
- if(buf[8+8+2] & 4) {
- print("drive w%d has exception #%.2x #%.2x\n", s,
- buf[8+8+4], buf[8+8+5]);
- goto bad;
- }
- break;
- }
- return;
- bad:
- /* panic("element") */ ;
- }
- /*
- * read all elements' status from jukebox w, move any discs in drives back
- * to their slots, and update and print software status.
- */
- static void
- positions(Juke *w)
- {
- int i, f;
- /* mark empty shelves */
- for(i=0; i<w->nse; i++)
- element(w, w->se0+i);
- for(i=0; i<w->nmt; i++)
- element(w, w->mt0+i);
- for(i=0; i<w->nie; i++)
- element(w, w->ie0+i);
- for(i=0; i<w->ndt; i++)
- element(w, w->dt0+i);
- f = 0;
- for(i=0; i<w->nse; i++)
- if(w->side[i].status == Sempty) {
- if(f) {
- print("r%d\n", i-1);
- f = 0;
- }
- } else {
- if(!f) {
- print("\tshelves r%d-", i);
- f = 1;
- }
- }
- if(f)
- print("r%d\n", i-1);
- }
- static void
- jinit(Juke *w, Device *d, int o)
- {
- int p;
- Device *dev = d;
- switch(d->type) {
- default:
- print("juke platter not (devmcat of) dev(l)worm: %Z\n", d);
- panic("jinit: type");
- case Devmcat:
- /*
- * we don't call mcatinit(d) here, so we have to set d->cat.ndev
- * ourselves.
- */
- for(d=d->cat.first; d; d=d->link)
- jinit(w, d, o++);
- dev->cat.ndev = o;
- break;
- case Devlworm:
- p = d->wren.targ;
- if(p < 0 || p >= w->nside)
- panic("jinit partition %Z", d);
- w->side[p].ord = o;
- /* FALL THROUGH */
- case Devworm:
- if(d->private) {
- print("juke platter private pointer set %p\n",
- d->private);
- panic("jinit: private");
- }
- d->private = w;
- break;
- }
- }
- Side*
- wormi(char *arg)
- {
- int i, j;
- Juke *w;
- Side *v;
- i = number(arg, -1, 10) - 1;
- w = jukelist;
- if(i < 0 || i >= w->nside) {
- print("bad unit number %s (%d)\n", arg, i+1);
- return 0;
- }
- j = i;
- if(j >= w->nse)
- j -= w->nse;
- if(j < w->nside) {
- v = &w->side[j];
- qlock(v);
- if(v->status == Sstart) {
- if(mmove(w, w->mt0, w->dt0+v->drive, v->elem, v->rot)) {
- qunlock(v);
- return 0;
- }
- v->status = Sunload;
- }
- qunlock(v);
- }
- j += w->nse;
- if(j < w->nside) {
- v = &w->side[j];
- qlock(v);
- if(v->status == Sstart) {
- if(mmove(w, w->mt0, w->dt0+v->drive, v->elem, v->rot)) {
- qunlock(v);
- return 0;
- }
- v->status = Sunload;
- }
- qunlock(v);
- }
- v = &w->side[i];
- qlock(v);
- return v;
- }
- static void
- cmd_wormoffline(int argc, char *argv[])
- {
- int u, i;
- Juke *w;
- if(argc <= 1) {
- print("usage: wormoffline drive\n");
- return;
- }
- u = number(argv[1], -1, 10);
- w = jukelist;
- if(u < 0 || u >= w->ndrive) {
- print("bad drive %s (0<=%d<%d)\n", argv[1], u, w->ndrive);
- return;
- }
- if(w->offline[u])
- print("drive %d already offline\n", u);
- w->offline[u] = 1;
- for(i=0; i<w->ndrive; i++)
- if(w->offline[i] == 0)
- return;
- print("that would take all drives offline\n");
- w->offline[u] = 0;
- }
- static void
- cmd_wormonline(int argc, char *argv[])
- {
- int u;
- Juke *w;
- if(argc <= 1) {
- print("usage: wormonline drive\n");
- return;
- }
- u = number(argv[1], -1, 10);
- w = jukelist;
- if(u < 0 || u >= w->ndrive) {
- print("bad drive %s (0<=%d<%d)\n", argv[1], u, w->ndrive);
- return;
- }
- if(w->offline[u] == 0)
- print("drive %d already online\n", u);
- w->offline[u] = 0;
- }
- void
- cmd_wormreset(int, char *[])
- {
- Juke *w;
- for(w=jukelist; w; w=w->link) {
- qlock(w);
- positions(w);
- qunlock(w);
- }
- }
- static void
- cmd_wormeject(int argc, char *argv[])
- {
- Juke *w;
- Side *v;
- if(argc <= 1) {
- print("usage: wormeject unit\n");
- return;
- }
- v = wormi(argv[1]);
- if(v == 0)
- return;
- w = jukelist;
- mmove(w, w->mt0, v->elem, w->ie0, 0);
- qunlock(v);
- }
- static void
- cmd_wormingest(int argc, char *argv[])
- {
- Juke *w;
- Side *v;
- if(argc <= 1) {
- print("usage: wormingest unit\n");
- return;
- }
- v = wormi(argv[1]);
- if(v == 0)
- return;
- w = jukelist;
- mmove(w, w->mt0, w->ie0, v->elem, 0);
- qunlock(v);
- }
- static void
- newside(Side *v, int rot, int elem)
- {
- qlock(v);
- qunlock(v);
- // v->name = "shelf";
- v->elem = elem;
- v->rot = rot;
- v->status = Sempty;
- v->time = toytime();
- }
- /*
- * query jukebox robotics for geometry;
- * argument is the wren dev of the changer.
- * result is actually Juke*, but that type is only known in this file.
- */
- void *
- querychanger(Device *xdev)
- {
- Juke *w;
- Side *v;
- int i;
- if (xdev == nil)
- panic("querychanger: nil Device");
- if(xdev->type != Devwren) {
- print("juke changer not wren %Z\n", xdev);
- goto bad;
- }
- for(w=jukelist; w; w=w->link)
- if(xdev == w->juke)
- return w;
- /*
- * allocate a juke structure
- * no locking problems.
- */
- w = malloc(sizeof(Juke));
- w->magic = Jukemagic;
- w->isfixedsize = FIXEDSIZE;
- w->link = jukelist;
- jukelist = w;
- print("alloc juke %Z\n", xdev);
- qlock(w);
- qunlock(w);
- // w->name = "juke";
- w->juke = xdev;
- w->robotdir = sdof(xdev);
- w->robot = openscsi(w->robotdir);
- if (w->robot == nil)
- panic("can't openscsi(%s): %r", w->robotdir);
- newscsi(xdev, w->robot);
- geometry(w);
- /*
- * pick up each side
- */
- w->nside = w->nse;
- if(w->rot)
- w->nside += w->nside;
- if(w->nside > MAXSIDE) {
- print("too many sides: %d max %d\n", w->nside, MAXSIDE);
- goto bad;
- }
- for(i=0; i < w->nse; i++) {
- v = &w->side[i];
- newside(v, 0, w->se0 + i);
- if(w->rot)
- newside(v + w->nse, 1, w->se0 + i);
- }
- positions(w);
- w->ndrive = w->ndt;
- if(w->ndrive > MAXDRIVE) {
- print("ndrives truncated to %d\n", MAXDRIVE);
- w->ndrive = MAXDRIVE;
- }
- /*
- * pick up each drive
- */
- for(i=0; i<w->ndrive; i++)
- w->drive[i] = devnone;
- return w;
- bad:
- panic("querychanger: %Z", xdev);
- return nil;
- }
- void
- jukeinit(Device *d)
- {
- Juke *w;
- Device *xdev;
- int i;
- static int beenhere = 0;
- /* j(w<changer>w<station0>...)(r<platters>) */
- if (d == nil)
- panic("jukeinit: nil Device");
- xdev = d->j.j;
- if(xdev == nil || xdev->type != Devmcat) {
- print("juke union not mcat\n");
- goto bad;
- }
- /*
- * pick up the changer device
- */
- xdev = xdev->cat.first;
- w = querychanger(xdev);
- if (!beenhere) {
- beenhere = 1;
- cmd_install("wormreset",
- "-- put drives back where jukebox thinks they belong",
- cmd_wormreset);
- cmd_install("wormeject", "unit -- shelf to outside",
- cmd_wormeject);
- cmd_install("wormingest", "unit -- outside to shelf",
- cmd_wormingest);
- cmd_install("wormoffline", "unit -- disable drive",
- cmd_wormoffline);
- cmd_install("wormonline", "unit -- enable drive",
- cmd_wormonline);
- }
- /* walk through the worm drives */
- i = 0;
- while(xdev = xdev->link) {
- if(xdev->type != Devwren) {
- print("drive not devwren: %Z\n", xdev);
- goto bad;
- }
- if(w->drive[i]->type != Devnone &&
- xdev != w->drive[i]) {
- print("double init drive %d %Z %Z\n",
- i, w->drive[i], xdev);
- goto bad;
- }
- if(i >= w->ndrive) {
- print("too many drives %Z\n", xdev);
- goto bad;
- }
- w->drive[i++] = xdev;
- }
- if(i <= 0) {
- print("no drives\n");
- goto bad;
- }
- /*
- * put w pointer in each platter
- */
- d->private = w;
- jinit(w, d->j.m, 0);
- w->probeok = 1;
- return;
- bad:
- panic("juke init");
- }
- /*
- * called periodically
- */
- void
- wormprobe(void)
- {
- int i, drive;
- Timet t;
- Side *v;
- Juke *w;
- t = toytime() - TWORM;
- for(w=jukelist; w; w=w->link) {
- if(w->probeok == 0 || !canqlock(w))
- continue;
- for(i=0; i<w->nside; i++) {
- v = &w->side[i];
- if(!canqlock(v))
- continue;
- if(v->status == Sstart && t > v->time) {
- drive = v->drive;
- print("\ttime r%ld drive %Z\n",
- v-w->side, w->drive[drive]);
- mmove(w, w->mt0, w->dt0+drive, v->elem, v->rot);
- v->status = Sunload;
- }
- qunlock(v);
- }
- qunlock(w);
- }
- }
|