juke.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167
  1. #include "all.h"
  2. #define SCSInone SCSIread
  3. #define MAXDRIVE 10
  4. #define MAXSIDE 500
  5. #define TWORM MINUTE(10)
  6. #define THYSTER SECOND(10)
  7. typedef struct Side Side;
  8. struct Side
  9. {
  10. QLock; /* protects loading/unloading */
  11. int elem; /* element number */
  12. int drive; /* if loaded, where */
  13. uchar status; /* Sunload, etc */
  14. uchar rot; /* if backside */
  15. int ord; /* ordinal number for labeling */
  16. long time; /* time since last access, to unspin */
  17. long stime; /* time since last spinup, for hysteresis */
  18. long nblock; /* number of native blocks */
  19. long block; /* bytes per native block */
  20. long mult; /* multiplier to get plan9 blocks */
  21. long max; /* max size in plan9 blocks */
  22. };
  23. typedef struct Juke Juke;
  24. struct Juke
  25. {
  26. QLock; /* protects drive mechanism */
  27. Side side[MAXSIDE];
  28. int nside; /* how many storage elements (*2 if rev) */
  29. int ndrive; /* number of transfer elements */
  30. Device* juke; /* devworm of changer */
  31. Device* drive[MAXDRIVE]; /* devworm for i/o */
  32. uchar offline[MAXDRIVE]; /* drives removed from service */
  33. long fixedsize; /* one size fits all */
  34. int probeok; /* wait for init to probe */
  35. /*
  36. * geometry returned by mode sense.
  37. * a *0 number (such as mt0) is the `element number' of the
  38. * first element of that type (e.g., mt, or motor transport).
  39. * an n* number is the quantity of them.
  40. */
  41. int mt0, nmt; /* motor transports (robot pickers) */
  42. int se0, nse; /* storage elements (discs, slots) */
  43. int ie0, nie; /* interchange elements (mailbox slots) */
  44. int dt0, ndt; /* drives (data transfer?) */
  45. int rot; /* if true, discs are double-sided */
  46. Juke* link;
  47. };
  48. static Juke* jukelist;
  49. enum
  50. {
  51. Sempty = 0, /* does not exist */
  52. Sunload, /* on the shelf */
  53. Sstart, /* loaded and spinning */
  54. };
  55. extern int FIXEDSIZE;
  56. static int wormsense(Device*);
  57. static Side* wormunit(Device*);
  58. static void shelves(void);
  59. static int mmove(Juke*, int, int, int, int);
  60. static int bestdrive(Juke*, int);
  61. static void waitready(Device*);
  62. static void element(Juke*, int);
  63. /*
  64. * mounts and spins up the device
  65. * locks the structure
  66. */
  67. static
  68. Side*
  69. wormunit(Device *d)
  70. {
  71. int p, s, drive;
  72. Side *v;
  73. Juke *w;
  74. uchar cmd[10], buf[8];
  75. w = d->private;
  76. p = d->wren.targ;
  77. if(p < 0 || p >= w->nside) {
  78. // panic("wormunit partition %Z\n", d);
  79. return 0;
  80. }
  81. /*
  82. * if disk is unloaded, must load it
  83. * into next (circular) logical unit
  84. */
  85. v = &w->side[p];
  86. qlock(v);
  87. if(v->status == Sunload) {
  88. for(;;) {
  89. qlock(w);
  90. drive = bestdrive(w, p);
  91. if(drive >= 0)
  92. break;
  93. qunlock(w);
  94. waitsec(100);
  95. }
  96. print(" load r%ld drive %Z\n", v-w->side, w->drive[drive]);
  97. if(mmove(w, w->mt0, v->elem, w->dt0+drive, v->rot)) {
  98. qunlock(w);
  99. goto sbad;
  100. }
  101. v->drive = drive;
  102. v->status = Sstart;
  103. v->stime = toytime();
  104. qunlock(w);
  105. waitready(w->drive[drive]);
  106. v->stime = toytime();
  107. }
  108. if(v->status != Sstart) {
  109. if(v->status == Sempty)
  110. print("worm: unit empty %Z\n", d);
  111. else
  112. print("worm: not started %Z\n", d);
  113. goto sbad;
  114. }
  115. v->time = toytime();
  116. if(v->block)
  117. return v;
  118. /*
  119. * capacity command
  120. */
  121. memset(cmd, 0, sizeof(cmd));
  122. memset(buf, 0, sizeof(buf));
  123. cmd[0] = 0x25; /* read capacity */
  124. s = scsiio(w->drive[v->drive], SCSIread,
  125. cmd, sizeof(cmd), buf, sizeof(buf));
  126. if(s)
  127. goto sbad;
  128. v->nblock =
  129. (buf[0]<<24) |
  130. (buf[1]<<16) |
  131. (buf[2]<<8) |
  132. (buf[3]<<0);
  133. v->block =
  134. (buf[4]<<24) |
  135. (buf[5]<<16) |
  136. (buf[6]<<8) |
  137. (buf[7]<<0);
  138. v->mult =
  139. (RBUFSIZE + v->block - 1) /
  140. v->block;
  141. v->max =
  142. (v->nblock + 1) / v->mult;
  143. print(" worm %Z: drive %Z\n", d, w->drive[v->drive]);
  144. print(" %ld blocks at %ld bytes each\n",
  145. v->nblock, v->block);
  146. print(" %ld logical blocks at %d bytes each\n",
  147. v->max, RBUFSIZE);
  148. print(" %ld multiplier\n",
  149. v->mult);
  150. if(d->type != Devlworm)
  151. return v;
  152. /* check for label */
  153. print("label %Z ordinal %d\n", d, v->ord);
  154. qunlock(v);
  155. return wormunit(d);
  156. sbad:
  157. qunlock(v);
  158. // panic("wormunit sbad");
  159. return 0;
  160. }
  161. static
  162. void
  163. waitready(Device *d)
  164. {
  165. uchar cmd[6];
  166. int s, e;
  167. for(e=0;e<100;e++) {
  168. memset(cmd, 0, sizeof(cmd));
  169. s = scsiio(d, SCSInone, cmd, sizeof(cmd), cmd, 0);
  170. if(s == 0)
  171. break;
  172. waitsec(100);
  173. }
  174. }
  175. static
  176. int
  177. bestdrive(Juke *w, int side)
  178. {
  179. Side *v, *bv[MAXDRIVE];
  180. int i, s, e, drive;
  181. long t, t0;
  182. loop:
  183. /* build table of what platters on what drives */
  184. for(i=0; i<w->ndt; i++)
  185. bv[i] = 0;
  186. v = &w->side[0];
  187. for(i=0; i<w->nside; i++, v++) {
  188. s = v->status;
  189. if(s == Sstart) {
  190. drive = v->drive;
  191. if(drive >= 0 && drive < w->ndt)
  192. bv[drive] = v;
  193. }
  194. }
  195. /*
  196. * find oldest drive, but must be
  197. * at least THYSTER old.
  198. */
  199. e = w->side[side].elem;
  200. t0 = toytime() - THYSTER;
  201. t = t0;
  202. drive = -1;
  203. for(i=0; i<w->ndt; i++) {
  204. v = bv[i];
  205. if(v == 0) { /* 2nd priority: empty drive */
  206. if(w->offline[i])
  207. continue;
  208. if(w->drive[i] != devnone) {
  209. drive = i;
  210. t = 0;
  211. }
  212. continue;
  213. }
  214. if(v->elem == e) { /* 1st priority: other side */
  215. drive = -1;
  216. if(v->stime < t0)
  217. drive = i;
  218. break;
  219. }
  220. if(v->stime < t) { /* 3rd priority: by time */
  221. drive = i;
  222. t = v->stime;
  223. }
  224. }
  225. if(drive >= 0) {
  226. v = bv[drive];
  227. if(v) {
  228. qlock(v);
  229. if(v->status != Sstart) {
  230. qunlock(v);
  231. goto loop;
  232. }
  233. print(" unload r%ld drive %Z\n",
  234. v-w->side, w->drive[drive]);
  235. if(mmove(w, w->mt0, w->dt0+drive, v->elem, v->rot)) {
  236. qunlock(v);
  237. goto loop;
  238. }
  239. v->status = Sunload;
  240. qunlock(v);
  241. }
  242. }
  243. return drive;
  244. }
  245. long
  246. wormsize(Device *d)
  247. {
  248. Side *v;
  249. Juke *w;
  250. long size;
  251. w = d->private;
  252. if(w->fixedsize) {
  253. size = w->fixedsize;
  254. goto out;
  255. }
  256. v = wormunit(d);
  257. if(v == 0)
  258. return 0;
  259. size = v->max;
  260. qunlock(v);
  261. if(FIXEDSIZE) // TODO? push FIXEDSIZE into Device or Juke struct
  262. w->fixedsize = size;
  263. out:
  264. if(d->type == Devlworm)
  265. return size-1;
  266. return size;
  267. }
  268. /*
  269. * return a Devjuke or an mcat (normally of sides) from within d (or nil).
  270. * if it's an mcat, the caller must walk it.
  271. */
  272. static Device *
  273. devtojuke(Device *d, Device *top)
  274. {
  275. while (d != nil)
  276. switch(d->type) {
  277. default:
  278. print("devtojuke: type of device %Z of %Z unknown\n",
  279. d, top);
  280. return nil;
  281. case Devjuke:
  282. /* jackpot! d->private is a (Juke *) with nside, &c. */
  283. /* FALL THROUGH */
  284. case Devmcat:
  285. case Devmlev:
  286. case Devmirr:
  287. /* squint hard & call an mlev or a mirr an mcat */
  288. return d;
  289. case Devworm:
  290. case Devlworm:
  291. /*
  292. * d->private is a (Juke *) with nside, etc.,
  293. * but we're not supposed to get here.
  294. */
  295. print("devtojuke: (l)worm %Z of %Z encountered\n",
  296. d, top);
  297. /* FALL THROUGH */
  298. case Devwren:
  299. case Devide:
  300. return nil;
  301. case Devcw:
  302. d = d->cw.w; /* usually juke */
  303. break;
  304. case Devro:
  305. d = d->ro.parent; /* cw */
  306. break;
  307. case Devfworm:
  308. d = d->fw.fw;
  309. break;
  310. case Devpart:
  311. d = d->part.d;
  312. break;
  313. case Devswab:
  314. d = d->swab.d;
  315. break;
  316. }
  317. return d;
  318. }
  319. static int
  320. devisside(Device *d)
  321. {
  322. return d->type == Devworm || d->type == Devlworm;
  323. }
  324. static Device *
  325. findside(Device *juke, int side, Device *top)
  326. {
  327. int i = 0;
  328. Device *mcat = juke->j.m, *x;
  329. Juke *w = juke->private;
  330. for (x = mcat->cat.first; x != nil; x = x->link) {
  331. if (!devisside(x)) {
  332. print("wormsizeside: %Z of %Z of %Z type not (l)worm\n",
  333. x, mcat, top);
  334. return nil;
  335. }
  336. i = x->wren.targ;
  337. if (i < 0 || i >= w->nside)
  338. panic("wormsizeside: side %d in %Z out of range",
  339. i, mcat);
  340. if (i == side)
  341. break;
  342. }
  343. if (x == nil)
  344. return nil;
  345. if (w->side[i].time == 0) {
  346. print("wormsizeside: side %d not in jukebox %Z\n", i, juke);
  347. return nil;
  348. }
  349. return x;
  350. }
  351. typedef struct {
  352. int sleft; /* sides still to visit to reach desired side */
  353. int starget; /* side of topdev we want */
  354. Device *topdev;
  355. int sawjuke; /* passed by a jukebox */
  356. int sized; /* flag: asked wormsize for size of starget */
  357. } Visit;
  358. /*
  359. * walk the Device tree from d looking for Devjukes, counting sides.
  360. * the main complication is mcats and the like with Devjukes in them.
  361. * use Devjuke's d->private as Juke* and see sides.
  362. */
  363. static long
  364. visitsides(Device *d, Device *parentj, Visit *vp)
  365. {
  366. long size = 0;
  367. Device *x;
  368. Juke *w;
  369. /*
  370. * find the first juke or mcat.
  371. * d==nil means we couldn't find one; typically harmless, due to a
  372. * mirror of dissimilar devices.
  373. */
  374. d = devtojuke(d, vp->topdev);
  375. if (d == nil || vp->sleft < 0)
  376. return 0;
  377. if (d->type == Devjuke) { /* jackpot! d->private is a (Juke *) */
  378. vp->sawjuke = 1;
  379. w = d->private;
  380. /*
  381. * if there aren't enough sides in this jukebox to reach
  382. * the desired one, subtract these sides and pass.
  383. */
  384. if (vp->sleft >= w->nside) {
  385. vp->sleft -= w->nside;
  386. return 0;
  387. }
  388. /* else this is the right juke, paw through mcat of sides */
  389. return visitsides(d->j.m, d, vp);
  390. }
  391. /*
  392. * d will usually be an mcat of sides, but it could be an mcat of
  393. * jukes, for example. in that case, we need to walk the mcat,
  394. * recursing as needed, until we find the right juke, then stop at
  395. * the right side within its mcat of sides, by comparing side
  396. * numbers, not just by counting (to allow for unused slots).
  397. */
  398. x = d->cat.first;
  399. if (x == nil) {
  400. print("visitsides: %Z of %Z: empty mcat\n", d, vp->topdev);
  401. return 0;
  402. }
  403. if (!devisside(x)) {
  404. for (; x != nil && !vp->sized; x = x->link)
  405. size = visitsides(x, parentj, vp);
  406. return size;
  407. }
  408. /* the side we want is in this jukebox, thus this mcat (d) */
  409. if (parentj == nil) {
  410. print("visitsides: no parent juke for sides mcat %Z\n", d);
  411. vp->sleft = -1;
  412. return 0;
  413. }
  414. if (d != parentj->j.m)
  415. panic("visitsides: mcat mismatch %Z vs %Z", d, parentj->j.m);
  416. x = findside(parentj, vp->sleft, vp->topdev);
  417. if (x == nil) {
  418. vp->sleft = -1;
  419. return 0;
  420. }
  421. /* we've turned vp->starget into the right Device* */
  422. vp->sleft = 0;
  423. vp->sized = 1;
  424. return wormsize(x);
  425. }
  426. /*
  427. * d must be, or be within, a filesystem config that also contains
  428. * the jukebox that `side' resides on.
  429. * d is normally a Devcw, but could be Devwren, Devide, Devpart, Devfworm,
  430. * etc. if called from chk.c Ctouch code. Note too that the worm part of
  431. * the Devcw might be other than a Devjuke.
  432. */
  433. long
  434. wormsizeside(Device *d, int side)
  435. {
  436. long size;
  437. Visit visit;
  438. memset(&visit, 0, sizeof visit);
  439. visit.starget = visit.sleft = side;
  440. visit.topdev = d;
  441. size = visitsides(d, nil, &visit);
  442. if (visit.sawjuke && (visit.sleft != 0 || !visit.sized)) {
  443. print("wormsizeside: fewer than %d sides in %Z\n", side, d);
  444. return 0;
  445. }
  446. return size;
  447. }
  448. /*
  449. * returns starts (in blocks) of side #side and #(side+1) of dev in *stp.
  450. * dev should be a Devcw.
  451. */
  452. void
  453. wormsidestarts(Device *dev, int side, Sidestarts *stp)
  454. {
  455. int s;
  456. long dstart;
  457. for (dstart = s = 0; s < side; s++)
  458. dstart += wormsizeside(dev, s);
  459. stp->sstart = dstart;
  460. stp->s1start = dstart + wormsizeside(dev, side);
  461. }
  462. static
  463. int
  464. wormiocmd(Device *d, int io, long b, void *c)
  465. {
  466. Side *v;
  467. Juke *w;
  468. long l, m;
  469. int s;
  470. uchar cmd[10];
  471. w = d->private;
  472. v = wormunit(d);
  473. if(v == 0)
  474. return 0x71;
  475. if(b >= v->max) {
  476. qunlock(v);
  477. print("worm: wormiocmd out of range %Z(%ld)\n", d, b);
  478. return 0x071;
  479. }
  480. memset(cmd, 0, sizeof(cmd));
  481. cmd[0] = 0x28; /* extended read */
  482. if(io != SCSIread)
  483. cmd[0] = 0x2a; /* extended write */
  484. m = v->mult;
  485. l = b * m;
  486. cmd[2] = l>>24;
  487. cmd[3] = l>>16;
  488. cmd[4] = l>>8;
  489. cmd[5] = l;
  490. cmd[7] = m>>8;
  491. cmd[8] = m;
  492. s = scsiio(w->drive[v->drive], io, cmd, sizeof(cmd), c, RBUFSIZE);
  493. qunlock(v);
  494. return s;
  495. }
  496. int
  497. wormread(Device *d, long b, void *c)
  498. {
  499. int s;
  500. s = wormiocmd(d, SCSIread, b, c);
  501. if(s) {
  502. print("wormread: %Z(%ld) bad status #%x\n", d, b, s);
  503. cons.nwormre++;
  504. return s;
  505. }
  506. return 0;
  507. }
  508. int
  509. wormwrite(Device *d, long b, void *c)
  510. {
  511. int s;
  512. s = wormiocmd(d, SCSIwrite, b, c);
  513. if(s) {
  514. print("wormwrite: %Z(%ld) bad status #%x\n", d, b, s);
  515. cons.nwormwe++;
  516. return s;
  517. }
  518. return 0;
  519. }
  520. static
  521. int
  522. mmove(Juke *w, int trans, int from, int to, int rot)
  523. {
  524. uchar cmd[12], buf[4];
  525. int s;
  526. static recur = 0;
  527. memset(cmd, 0, sizeof(cmd));
  528. cmd[0] = 0xa5; /* move medium */
  529. cmd[2] = trans>>8;
  530. cmd[3] = trans;
  531. cmd[4] = from>>8;
  532. cmd[5] = from;
  533. cmd[6] = to>>8;
  534. cmd[7] = to;
  535. if(rot)
  536. cmd[10] = 1;
  537. s = scsiio(w->juke, SCSInone, cmd, sizeof(cmd), buf, 0);
  538. if(s) {
  539. print("scsio status #%x\n", s);
  540. print("move medium t=%d fr=%d to=%d rot=%d\n",
  541. trans, from, to, rot);
  542. // panic("mmove");
  543. if(recur == 0) {
  544. recur = 1;
  545. print("element from=%d\n", from);
  546. element(w, from);
  547. print("element to=%d\n", to);
  548. element(w, to);
  549. print("element trans=%d\n", trans);
  550. element(w, trans);
  551. recur = 0;
  552. }
  553. return 1;
  554. }
  555. return 0;
  556. }
  557. static
  558. void
  559. geometry(Juke *w)
  560. {
  561. int s;
  562. uchar cmd[6], buf[4+20];
  563. memset(cmd, 0, sizeof(cmd));
  564. memset(buf, 0, sizeof(buf));
  565. cmd[0] = 0x1a; /* mode sense */
  566. cmd[2] = 0x1d; /* element address assignment */
  567. cmd[4] = sizeof(buf); /* allocation length */
  568. s = scsiio(w->juke, SCSIread, cmd, sizeof(cmd), buf, sizeof(buf));
  569. if(s)
  570. panic("geometry #%x\n", s);
  571. w->mt0 = (buf[4+2]<<8) | buf[4+3];
  572. w->nmt = (buf[4+4]<<8) | buf[4+5];
  573. w->se0 = (buf[4+6]<<8) | buf[4+7];
  574. w->nse = (buf[4+8]<<8) | buf[4+9];
  575. w->ie0 = (buf[4+10]<<8) | buf[4+11];
  576. w->nie = (buf[4+12]<<8) | buf[4+13];
  577. w->dt0 = (buf[4+14]<<8) | buf[4+15];
  578. w->ndt = (buf[4+16]<<8) | buf[4+17];
  579. memset(cmd, 0, 6);
  580. memset(buf, 0, sizeof(buf));
  581. cmd[0] = 0x1a; /* mode sense */
  582. cmd[2] = 0x1e; /* transport geometry */
  583. cmd[4] = sizeof(buf); /* allocation length */
  584. s = scsiio(w->juke, SCSIread, cmd, sizeof(cmd), buf, sizeof(buf));
  585. if(s)
  586. panic("geometry #%x\n", s);
  587. w->rot = buf[4+2] & 1;
  588. print(" mt %d %d\n", w->mt0, w->nmt);
  589. print(" se %d %d\n", w->se0, w->nse);
  590. print(" ie %d %d\n", w->ie0, w->nie);
  591. print(" dt %d %d\n", w->dt0, w->ndt);
  592. print(" rot %d\n", w->rot);
  593. prflush();
  594. }
  595. static
  596. void
  597. element(Juke *w, int e)
  598. {
  599. uchar cmd[12], buf[8+8+88];
  600. int s, t;
  601. //loop:
  602. memset(cmd, 0, sizeof(cmd));
  603. memset(buf, 0, sizeof(buf));
  604. cmd[0] = 0xb8; /* read element status */
  605. cmd[2] = e>>8; /* starting element */
  606. cmd[3] = e;
  607. cmd[5] = 1; /* number of elements */
  608. cmd[9] = sizeof(buf); /* allocation length */
  609. s = scsiio(w->juke, SCSIread, cmd, sizeof(cmd), buf, sizeof(buf));
  610. if(s) {
  611. print("scsiio #%x\n", s);
  612. goto bad;
  613. }
  614. s = (buf[0]<<8) | buf[1];
  615. if(s != e) {
  616. print("element = %d\n", s);
  617. goto bad;
  618. }
  619. if(buf[3] != 1) {
  620. print("number reported = %d\n", buf[3]);
  621. goto bad;
  622. }
  623. s = (buf[8+8+0]<<8) | buf[8+8+1];
  624. if(s != e) {
  625. print("element1 = %d\n", s);
  626. goto bad;
  627. }
  628. switch(buf[8+0]) { /* element type */
  629. default:
  630. print("unknown element %d: %d\n", e, buf[8+0]);
  631. goto bad;
  632. case 1: /* transport */
  633. s = e - w->mt0;
  634. if(s < 0 || s >= w->nmt)
  635. goto bad;
  636. if(buf[8+8+2] & 1)
  637. print("transport %d full %d.%d\n", s,
  638. (buf[8+8+10]<<8) | buf[8+8+11],
  639. (buf[8+8+9]>>6) & 1);
  640. break;
  641. case 2: /* storage */
  642. s = e - w->se0;
  643. if(s < 0 || s >= w->nse)
  644. goto bad;
  645. w->side[s].status = Sempty;
  646. if(buf[8+8+2] & 1)
  647. w->side[s].status = Sunload;
  648. if(w->rot)
  649. w->side[w->nse+s].status = w->side[s].status;
  650. break;
  651. case 3: /* import/export */
  652. s = e - w->ie0;
  653. if(s < 0 || s >= w->nie)
  654. goto bad;
  655. print("import/export %d #%.2x %d.%d\n", s,
  656. buf[8+8+2],
  657. (buf[8+8+10]<<8) | buf[8+8+11],
  658. (buf[8+8+9]>>6) & 1);
  659. break;
  660. case 4: /* data transfer */
  661. s = e - w->dt0;
  662. if(s < 0 || s >= w->ndt)
  663. goto bad;
  664. print("data transfer %d #%.2x %d.%d\n", s,
  665. buf[8+8+2],
  666. (buf[8+8+10]<<8) | buf[8+8+11],
  667. (buf[8+8+9]>>6) & 1);
  668. if(buf[8+8+2] & 1) {
  669. t = ((buf[8+8+10]<<8) | buf[8+8+11]) - w->se0;
  670. if (t < 0 || t >= w->nse || t >= MAXSIDE ||
  671. s >= MAXDRIVE) {
  672. print(
  673. "element: juke %Z lies; claims side %d is in drive %d\n",
  674. w->juke, t, s); /* lying sack of ... */
  675. /*
  676. * at minimum, we've avoided corrupting our
  677. * data structures. if we know that numbers
  678. * like w->nside are valid here, we could use
  679. * them in more stringent tests.
  680. * perhaps should whack the jukebox upside the
  681. * head here to knock some sense into it.
  682. */
  683. goto bad;
  684. }
  685. print("r%d in drive %d\n", t, s);
  686. if(mmove(w, w->mt0, w->dt0+s, w->se0+t, (buf[8+8+9]>>6) & 1)) {
  687. print("mmove initial unload\n");
  688. goto bad;
  689. }
  690. w->side[t].status = Sunload;
  691. if(w->rot)
  692. w->side[w->nse+t].status = Sunload;
  693. }
  694. if(buf[8+8+2] & 4) {
  695. print("drive w%d has exception #%.2x #%.2x\n", s,
  696. buf[8+8+4], buf[8+8+5]);
  697. goto bad;
  698. }
  699. break;
  700. }
  701. return;
  702. bad:
  703. // panic("element");
  704. return;
  705. }
  706. static
  707. void
  708. positions(Juke *w)
  709. {
  710. int i, f;
  711. /* mark empty shelves */
  712. for(i=0; i<w->nse; i++)
  713. element(w, w->se0+i);
  714. for(i=0; i<w->nmt; i++)
  715. element(w, w->mt0+i);
  716. for(i=0; i<w->nie; i++)
  717. element(w, w->ie0+i);
  718. for(i=0; i<w->ndt; i++)
  719. element(w, w->dt0+i);
  720. f = 0;
  721. for(i=0; i<w->nse; i++) {
  722. if(w->side[i].status == Sempty) {
  723. if(f) {
  724. print("r%d\n", i-1);
  725. f = 0;
  726. }
  727. } else {
  728. if(!f) {
  729. print(" shelves r%d-", i);
  730. f = 1;
  731. }
  732. }
  733. }
  734. if(f)
  735. print("r%d\n", i-1);
  736. }
  737. static
  738. void
  739. jinit(Juke *w, Device *d, int o)
  740. {
  741. int p;
  742. Device *dev = d;
  743. switch(d->type) {
  744. default:
  745. print("juke platter not (devmcat of) dev(l)worm: %Z\n", d);
  746. goto bad;
  747. case Devmcat:
  748. /*
  749. * we don't call mcatinit(d) here, so we have to set d->cat.ndev
  750. * ourselves.
  751. */
  752. for(d=d->cat.first; d; d=d->link)
  753. jinit(w, d, o++);
  754. dev->cat.ndev = o;
  755. break;
  756. case Devlworm:
  757. p = d->wren.targ;
  758. if(p < 0 || p >= w->nside)
  759. panic("jinit partition %Z\n", d);
  760. w->side[p].ord = o;
  761. case Devworm:
  762. if(d->private) {
  763. print("juke platter private pointer set %p\n",
  764. d->private);
  765. goto bad;
  766. }
  767. d->private = w;
  768. break;
  769. }
  770. return;
  771. bad:
  772. panic("jinit");
  773. }
  774. Side*
  775. wormi(char *arg)
  776. {
  777. int i, j;
  778. Juke *w;
  779. Side *v;
  780. i = number(arg, -1, 10) - 1;
  781. w = jukelist;
  782. if(i < 0 || i >= w->nside) {
  783. print("bad unit number %s (%d)\n", arg, i+1);
  784. return 0;
  785. }
  786. j = i;
  787. if(j >= w->nse)
  788. j -= w->nse;
  789. if(j < w->nside) {
  790. v = &w->side[j];
  791. qlock(v);
  792. if(v->status == Sstart) {
  793. if(mmove(w, w->mt0, w->dt0+v->drive, v->elem, v->rot)) {
  794. qunlock(v);
  795. return 0;
  796. }
  797. v->status = Sunload;
  798. }
  799. qunlock(v);
  800. }
  801. j += w->nse;
  802. if(j < w->nside) {
  803. v = &w->side[j];
  804. qlock(v);
  805. if(v->status == Sstart) {
  806. if(mmove(w, w->mt0, w->dt0+v->drive, v->elem, v->rot)) {
  807. qunlock(v);
  808. return 0;
  809. }
  810. v->status = Sunload;
  811. }
  812. qunlock(v);
  813. }
  814. v = &w->side[i];
  815. qlock(v);
  816. return v;
  817. }
  818. static
  819. void
  820. cmd_wormoffline(int argc, char *argv[])
  821. {
  822. int u, i;
  823. Juke *w;
  824. if(argc <= 1) {
  825. print("usage: wormoffline drive\n");
  826. return;
  827. }
  828. u = number(argv[1], -1, 10);
  829. w = jukelist;
  830. if(u < 0 || u >= w->ndrive) {
  831. print("bad drive %s (0<=%d<%d)\n", argv[1], u, w->ndrive);
  832. return;
  833. }
  834. if(w->offline[u])
  835. print("drive %d already offline\n", u);
  836. w->offline[u] = 1;
  837. for(i=0; i<w->ndrive; i++)
  838. if(w->offline[i] == 0)
  839. return;
  840. print("that would take all drives offline\n");
  841. w->offline[u] = 0;
  842. }
  843. static
  844. void
  845. cmd_wormonline(int argc, char *argv[])
  846. {
  847. int u;
  848. Juke *w;
  849. if(argc <= 1) {
  850. print("usage: wormonline drive\n");
  851. return;
  852. }
  853. u = number(argv[1], -1, 10);
  854. w = jukelist;
  855. if(u < 0 || u >= w->ndrive) {
  856. print("bad drive %s (0<=%d<%d)\n", argv[1], u, w->ndrive);
  857. return;
  858. }
  859. if(w->offline[u] == 0)
  860. print("drive %d already online\n", u);
  861. w->offline[u] = 0;
  862. }
  863. static
  864. void
  865. cmd_wormreset(int, char *[])
  866. {
  867. Juke *w;
  868. for(w=jukelist; w; w=w->link) {
  869. qlock(w);
  870. positions(w);
  871. qunlock(w);
  872. }
  873. }
  874. static
  875. void
  876. cmd_wormeject(int argc, char *argv[])
  877. {
  878. Juke *w;
  879. Side *v;
  880. if(argc <= 1) {
  881. print("usage: wormeject unit\n");
  882. return;
  883. }
  884. v = wormi(argv[1]);
  885. if(v == 0)
  886. return;
  887. w = jukelist;
  888. mmove(w, w->mt0, v->elem, w->ie0, 0);
  889. qunlock(v);
  890. }
  891. static
  892. void
  893. cmd_wormingest(int argc, char *argv[])
  894. {
  895. Juke *w;
  896. Side *v;
  897. if(argc <= 1) {
  898. print("usage: wormingest unit\n");
  899. return;
  900. }
  901. v = wormi(argv[1]);
  902. if(v == 0)
  903. return;
  904. w = jukelist;
  905. mmove(w, w->mt0, w->ie0, v->elem, 0);
  906. qunlock(v);
  907. }
  908. void
  909. jukeinit(Device *d)
  910. {
  911. Juke *w;
  912. Device *xdev;
  913. Side *v;
  914. int i;
  915. /* j(w<changer>w<station0>...)(r<platters>) */
  916. xdev = d->j.j;
  917. if(xdev->type != Devmcat) {
  918. print("juke union not mcat\n");
  919. goto bad;
  920. }
  921. /*
  922. * pick up the changer device
  923. */
  924. xdev = xdev->cat.first;
  925. if(xdev->type != Devwren) {
  926. print("juke changer not wren %Z\n", xdev);
  927. goto bad;
  928. }
  929. for(w=jukelist; w; w=w->link)
  930. if(xdev == w->juke)
  931. goto found;
  932. /*
  933. * allocate a juke structure
  934. * no locking problems.
  935. */
  936. w = ialloc(sizeof(Juke), 0);
  937. w->link = jukelist;
  938. jukelist = w;
  939. print("alloc juke %Z\n", xdev);
  940. qlock(w);
  941. qunlock(w);
  942. w->name = "juke";
  943. w->juke = xdev;
  944. geometry(w);
  945. /*
  946. * pick up each side
  947. */
  948. w->nside = w->nse;
  949. if(w->rot)
  950. w->nside += w->nside;
  951. if(w->nside > MAXSIDE) {
  952. print("too many sides: %d max %d\n", w->nside, MAXSIDE);
  953. goto bad;
  954. }
  955. for(i=0; i<w->nse; i++) {
  956. v = &w->side[i];
  957. qlock(v);
  958. qunlock(v);
  959. v->name = "shelf";
  960. v->elem = w->se0 + i;
  961. v->rot = 0;
  962. v->status = Sempty;
  963. v->time = toytime();
  964. if(w->rot) {
  965. v += w->nse;
  966. qlock(v);
  967. qunlock(v);
  968. v->name = "shelf";
  969. v->elem = w->se0 + i;
  970. v->rot = 1;
  971. v->status = Sempty;
  972. v->time = toytime();
  973. }
  974. }
  975. positions(w);
  976. w->ndrive = w->ndt;
  977. if(w->ndrive > MAXDRIVE) {
  978. print("ndrives truncated to %d\n", MAXDRIVE);
  979. w->ndrive = MAXDRIVE;
  980. }
  981. /*
  982. * pick up each drive
  983. */
  984. for(i=0; i<w->ndrive; i++)
  985. w->drive[i] = devnone;
  986. cmd_install("wormreset", "-- put drives back where jukebox thinks they belong", cmd_wormreset);
  987. cmd_install("wormeject", "unit -- shelf to outside", cmd_wormeject);
  988. cmd_install("wormingest", "unit -- outside to shelf", cmd_wormingest);
  989. cmd_install("wormoffline", "unit -- disable drive", cmd_wormoffline);
  990. cmd_install("wormonline", "unit -- enable drive", cmd_wormonline);
  991. found:
  992. i = 0;
  993. while(xdev = xdev->link) {
  994. if(xdev->type != Devwren) {
  995. print("drive not devwren: %Z\n", xdev);
  996. goto bad;
  997. }
  998. if(w->drive[i]->type != Devnone &&
  999. xdev != w->drive[i]) {
  1000. print("double init drive %d %Z %Z\n", i, w->drive[i], xdev);
  1001. goto bad;
  1002. }
  1003. if(i >= w->ndrive) {
  1004. print("too many drives %Z\n", xdev);
  1005. goto bad;
  1006. }
  1007. w->drive[i++] = xdev;
  1008. }
  1009. if(i <= 0) {
  1010. print("no drives\n");
  1011. goto bad;
  1012. }
  1013. /*
  1014. * put w pointer in each platter
  1015. */
  1016. d->private = w;
  1017. jinit(w, d->j.m, 0);
  1018. w->probeok = 1;
  1019. return;
  1020. bad:
  1021. panic("juke init");
  1022. }
  1023. int
  1024. dowcp(void)
  1025. {
  1026. return 0;
  1027. }
  1028. /*
  1029. * called periodically
  1030. */
  1031. void
  1032. wormprobe(void)
  1033. {
  1034. int i, drive;
  1035. long t;
  1036. Side *v;
  1037. Juke *w;
  1038. t = toytime() - TWORM;
  1039. for(w=jukelist; w; w=w->link) {
  1040. if(w->probeok == 0 || !canqlock(w))
  1041. continue;
  1042. for(i=0; i<w->nside; i++) {
  1043. v = &w->side[i];
  1044. if(!canqlock(v))
  1045. continue;
  1046. if(v->status == Sstart && t > v->time) {
  1047. drive = v->drive;
  1048. print(" time r%ld drive %Z\n",
  1049. v-w->side, w->drive[drive]);
  1050. mmove(w, w->mt0, w->dt0+drive, v->elem, v->rot);
  1051. v->status = Sunload;
  1052. }
  1053. qunlock(v);
  1054. }
  1055. qunlock(w);
  1056. }
  1057. }