juke.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152
  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. Timet time; /* time since last access, to unspin */
  17. Timet 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. Timet 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. Devsize
  246. wormsize(Device *d)
  247. {
  248. Side *v;
  249. Juke *w;
  250. Devsize size;
  251. w = d->private;
  252. if(w->fixedsize)
  253. size = w->fixedsize;
  254. else {
  255. v = wormunit(d);
  256. if(v == 0)
  257. return 0;
  258. size = v->max;
  259. qunlock(v);
  260. if(FIXEDSIZE) // TODO? push FIXEDSIZE into Device or Juke struct
  261. w->fixedsize = size;
  262. }
  263. if(d->type == Devlworm)
  264. return size-1;
  265. return size;
  266. }
  267. /*
  268. * return a Devjuke or an mcat (normally of sides) from within d (or nil).
  269. * if it's an mcat, the caller must walk it.
  270. */
  271. static Device *
  272. devtojuke(Device *d, Device *top)
  273. {
  274. while (d != nil)
  275. switch(d->type) {
  276. default:
  277. print("devtojuke: type of device %Z of %Z unknown\n",
  278. d, top);
  279. return nil;
  280. case Devjuke:
  281. /* jackpot! d->private is a (Juke *) with nside, &c. */
  282. /* FALL THROUGH */
  283. case Devmcat:
  284. case Devmlev:
  285. case Devmirr:
  286. /* squint hard & call an mlev or a mirr an mcat */
  287. return d;
  288. case Devworm:
  289. case Devlworm:
  290. /*
  291. * d->private is a (Juke *) with nside, etc.,
  292. * but we're not supposed to get here.
  293. */
  294. print("devtojuke: (l)worm %Z of %Z encountered\n",
  295. d, top);
  296. /* FALL THROUGH */
  297. case Devwren:
  298. case Devide:
  299. return nil;
  300. case Devcw:
  301. d = d->cw.w; /* usually juke */
  302. break;
  303. case Devro:
  304. d = d->ro.parent; /* cw */
  305. break;
  306. case Devfworm:
  307. d = d->fw.fw;
  308. break;
  309. case Devpart:
  310. d = d->part.d;
  311. break;
  312. case Devswab:
  313. d = d->swab.d;
  314. break;
  315. }
  316. return d;
  317. }
  318. static int
  319. devisside(Device *d)
  320. {
  321. return d->type == Devworm || d->type == Devlworm;
  322. }
  323. static Device *
  324. findside(Device *juke, int side, Device *top)
  325. {
  326. int i = 0;
  327. Device *mcat = juke->j.m, *x;
  328. Juke *w = juke->private;
  329. for (x = mcat->cat.first; x != nil; x = x->link) {
  330. if (!devisside(x)) {
  331. print("wormsizeside: %Z of %Z of %Z type not (l)worm\n",
  332. x, mcat, top);
  333. return nil;
  334. }
  335. i = x->wren.targ;
  336. if (i < 0 || i >= w->nside)
  337. panic("wormsizeside: side %d in %Z out of range",
  338. i, mcat);
  339. if (i == side)
  340. break;
  341. }
  342. if (x == nil)
  343. return nil;
  344. if (w->side[i].time == 0) {
  345. print("wormsizeside: side %d not in jukebox %Z\n", i, juke);
  346. return nil;
  347. }
  348. return x;
  349. }
  350. typedef struct {
  351. int sleft; /* sides still to visit to reach desired side */
  352. int starget; /* side of topdev we want */
  353. Device *topdev;
  354. int sawjuke; /* passed by a jukebox */
  355. int sized; /* flag: asked wormsize for size of starget */
  356. } Visit;
  357. /*
  358. * walk the Device tree from d looking for Devjukes, counting sides.
  359. * the main complication is mcats and the like with Devjukes in them.
  360. * use Devjuke's d->private as Juke* and see sides.
  361. */
  362. static Off
  363. visitsides(Device *d, Device *parentj, Visit *vp)
  364. {
  365. Off size = 0;
  366. Device *x;
  367. Juke *w;
  368. /*
  369. * find the first juke or mcat.
  370. * d==nil means we couldn't find one; typically harmless, due to a
  371. * mirror of dissimilar devices.
  372. */
  373. d = devtojuke(d, vp->topdev);
  374. if (d == nil || vp->sleft < 0)
  375. return 0;
  376. if (d->type == Devjuke) { /* jackpot! d->private is a (Juke *) */
  377. vp->sawjuke = 1;
  378. w = d->private;
  379. /*
  380. * if there aren't enough sides in this jukebox to reach
  381. * the desired one, subtract these sides and pass.
  382. */
  383. if (vp->sleft >= w->nside) {
  384. vp->sleft -= w->nside;
  385. return 0;
  386. }
  387. /* else this is the right juke, paw through mcat of sides */
  388. return visitsides(d->j.m, d, vp);
  389. }
  390. /*
  391. * d will usually be an mcat of sides, but it could be an mcat of
  392. * jukes, for example. in that case, we need to walk the mcat,
  393. * recursing as needed, until we find the right juke, then stop at
  394. * the right side within its mcat of sides, by comparing side
  395. * numbers, not just by counting (to allow for unused slots).
  396. */
  397. x = d->cat.first;
  398. if (x == nil) {
  399. print("visitsides: %Z of %Z: empty mcat\n", d, vp->topdev);
  400. return 0;
  401. }
  402. if (!devisside(x)) {
  403. for (; x != nil && !vp->sized; x = x->link)
  404. size = visitsides(x, parentj, vp);
  405. return size;
  406. }
  407. /* the side we want is in this jukebox, thus this mcat (d) */
  408. if (parentj == nil) {
  409. print("visitsides: no parent juke for sides mcat %Z\n", d);
  410. vp->sleft = -1;
  411. return 0;
  412. }
  413. if (d != parentj->j.m)
  414. panic("visitsides: mcat mismatch %Z vs %Z", d, parentj->j.m);
  415. x = findside(parentj, vp->sleft, vp->topdev);
  416. if (x == nil) {
  417. vp->sleft = -1;
  418. return 0;
  419. }
  420. /* we've turned vp->starget into the right Device* */
  421. vp->sleft = 0;
  422. vp->sized = 1;
  423. return wormsize(x);
  424. }
  425. /*
  426. * d must be, or be within, a filesystem config that also contains
  427. * the jukebox that `side' resides on.
  428. * d is normally a Devcw, but could be Devwren, Devide, Devpart, Devfworm,
  429. * etc. if called from chk.c Ctouch code. Note too that the worm part of
  430. * the Devcw might be other than a Devjuke.
  431. */
  432. Devsize
  433. wormsizeside(Device *d, int side)
  434. {
  435. Devsize size;
  436. Visit visit;
  437. memset(&visit, 0, sizeof visit);
  438. visit.starget = visit.sleft = side;
  439. visit.topdev = d;
  440. size = visitsides(d, nil, &visit);
  441. if (visit.sawjuke && (visit.sleft != 0 || !visit.sized)) {
  442. print("wormsizeside: fewer than %d sides in %Z\n", side, d);
  443. return 0;
  444. }
  445. return size;
  446. }
  447. /*
  448. * returns starts (in blocks) of side #side and #(side+1) of dev in *stp.
  449. * dev should be a Devcw.
  450. */
  451. void
  452. wormsidestarts(Device *dev, int side, Sidestarts *stp)
  453. {
  454. int s;
  455. Devsize dstart;
  456. for (dstart = s = 0; s < side; s++)
  457. dstart += wormsizeside(dev, s);
  458. stp->sstart = dstart;
  459. stp->s1start = dstart + wormsizeside(dev, side);
  460. }
  461. static
  462. int
  463. wormiocmd(Device *d, int io, Off b, void *c)
  464. {
  465. Side *v;
  466. Juke *w;
  467. Off l;
  468. int s;
  469. long m;
  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(%lld)\n", d, (Wideoff)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, Off b, void *c)
  498. {
  499. int s;
  500. s = wormiocmd(d, SCSIread, b, c);
  501. if(s) {
  502. print("wormread: %Z(%lld) bad status #%x\n", d, (Wideoff)b, s);
  503. cons.nwormre++;
  504. return s;
  505. }
  506. return 0;
  507. }
  508. int
  509. wormwrite(Device *d, Off b, void *c)
  510. {
  511. int s;
  512. s = wormiocmd(d, SCSIwrite, b, c);
  513. if(s) {
  514. print("wormwrite: %Z(%lld) bad status #%x\n", d, (Wideoff)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. memset(cmd, 0, sizeof(cmd));
  602. memset(buf, 0, sizeof(buf));
  603. cmd[0] = 0xb8; /* read element status */
  604. cmd[2] = e>>8; /* starting element */
  605. cmd[3] = e;
  606. cmd[5] = 1; /* number of elements */
  607. cmd[9] = sizeof(buf); /* allocation length */
  608. s = scsiio(w->juke, SCSIread, cmd, sizeof(cmd), buf, sizeof(buf));
  609. if(s) {
  610. print("scsiio #%x\n", s);
  611. goto bad;
  612. }
  613. s = (buf[0]<<8) | buf[1];
  614. if(s != e) {
  615. print("element = %d\n", s);
  616. goto bad;
  617. }
  618. if(buf[3] != 1) {
  619. print("number reported = %d\n", buf[3]);
  620. goto bad;
  621. }
  622. s = (buf[8+8+0]<<8) | buf[8+8+1];
  623. if(s != e) {
  624. print("element1 = %d\n", s);
  625. goto bad;
  626. }
  627. switch(buf[8+0]) { /* element type */
  628. default:
  629. print("unknown element %d: %d\n", e, buf[8+0]);
  630. goto bad;
  631. case 1: /* transport */
  632. s = e - w->mt0;
  633. if(s < 0 || s >= w->nmt)
  634. goto bad;
  635. if(buf[8+8+2] & 1)
  636. print("transport %d full %d.%d\n", s,
  637. (buf[8+8+10]<<8) | buf[8+8+11],
  638. (buf[8+8+9]>>6) & 1);
  639. break;
  640. case 2: /* storage */
  641. s = e - w->se0;
  642. if(s < 0 || s >= w->nse)
  643. goto bad;
  644. w->side[s].status = Sempty;
  645. if(buf[8+8+2] & 1)
  646. w->side[s].status = Sunload;
  647. if(w->rot)
  648. w->side[w->nse+s].status = w->side[s].status;
  649. break;
  650. case 3: /* import/export */
  651. s = e - w->ie0;
  652. if(s < 0 || s >= w->nie)
  653. goto bad;
  654. print("import/export %d #%.2x %d.%d\n", s,
  655. buf[8+8+2],
  656. (buf[8+8+10]<<8) | buf[8+8+11],
  657. (buf[8+8+9]>>6) & 1);
  658. break;
  659. case 4: /* data transfer */
  660. s = e - w->dt0;
  661. if(s < 0 || s >= w->ndt)
  662. goto bad;
  663. print("data transfer %d #%.2x %d.%d\n", s,
  664. buf[8+8+2],
  665. (buf[8+8+10]<<8) | buf[8+8+11],
  666. (buf[8+8+9]>>6) & 1);
  667. if(buf[8+8+2] & 1) {
  668. t = ((buf[8+8+10]<<8) | buf[8+8+11]) - w->se0;
  669. if (t < 0 || t >= w->nse || t >= MAXSIDE ||
  670. s >= MAXDRIVE) {
  671. print(
  672. "element: juke %Z lies; claims side %d is in drive %d\n",
  673. w->juke, t, s); /* lying sack of ... */
  674. /*
  675. * at minimum, we've avoided corrupting our
  676. * data structures. if we know that numbers
  677. * like w->nside are valid here, we could use
  678. * them in more stringent tests.
  679. * perhaps should whack the jukebox upside the
  680. * head here to knock some sense into it.
  681. */
  682. goto bad;
  683. }
  684. print("r%d in drive %d\n", t, s);
  685. if(mmove(w, w->mt0, w->dt0+s, w->se0+t, (buf[8+8+9]>>6) & 1)) {
  686. print("mmove initial unload\n");
  687. goto bad;
  688. }
  689. w->side[t].status = Sunload;
  690. if(w->rot)
  691. w->side[w->nse+t].status = Sunload;
  692. }
  693. if(buf[8+8+2] & 4) {
  694. print("drive w%d has exception #%.2x #%.2x\n", s,
  695. buf[8+8+4], buf[8+8+5]);
  696. goto bad;
  697. }
  698. break;
  699. }
  700. return;
  701. bad:
  702. /* panic("element") */ ;
  703. }
  704. static
  705. void
  706. positions(Juke *w)
  707. {
  708. int i, f;
  709. /* mark empty shelves */
  710. for(i=0; i<w->nse; i++)
  711. element(w, w->se0+i);
  712. for(i=0; i<w->nmt; i++)
  713. element(w, w->mt0+i);
  714. for(i=0; i<w->nie; i++)
  715. element(w, w->ie0+i);
  716. for(i=0; i<w->ndt; i++)
  717. element(w, w->dt0+i);
  718. f = 0;
  719. for(i=0; i<w->nse; i++) {
  720. if(w->side[i].status == Sempty) {
  721. if(f) {
  722. print("r%d\n", i-1);
  723. f = 0;
  724. }
  725. } else {
  726. if(!f) {
  727. print(" shelves r%d-", i);
  728. f = 1;
  729. }
  730. }
  731. }
  732. if(f)
  733. print("r%d\n", i-1);
  734. }
  735. static
  736. void
  737. jinit(Juke *w, Device *d, int o)
  738. {
  739. int p;
  740. Device *dev = d;
  741. switch(d->type) {
  742. default:
  743. print("juke platter not (devmcat of) dev(l)worm: %Z\n", d);
  744. panic("jinit: type");
  745. case Devmcat:
  746. /*
  747. * we don't call mcatinit(d) here, so we have to set d->cat.ndev
  748. * ourselves.
  749. */
  750. for(d=d->cat.first; d; d=d->link)
  751. jinit(w, d, o++);
  752. dev->cat.ndev = o;
  753. break;
  754. case Devlworm:
  755. p = d->wren.targ;
  756. if(p < 0 || p >= w->nside)
  757. panic("jinit partition %Z\n", d);
  758. w->side[p].ord = o;
  759. case Devworm:
  760. if(d->private) {
  761. print("juke platter private pointer set %p\n",
  762. d->private);
  763. panic("jinit: private");
  764. }
  765. d->private = w;
  766. break;
  767. }
  768. }
  769. Side*
  770. wormi(char *arg)
  771. {
  772. int i, j;
  773. Juke *w;
  774. Side *v;
  775. i = number(arg, -1, 10) - 1;
  776. w = jukelist;
  777. if(i < 0 || i >= w->nside) {
  778. print("bad unit number %s (%d)\n", arg, i+1);
  779. return 0;
  780. }
  781. j = i;
  782. if(j >= w->nse)
  783. j -= w->nse;
  784. if(j < w->nside) {
  785. v = &w->side[j];
  786. qlock(v);
  787. if(v->status == Sstart) {
  788. if(mmove(w, w->mt0, w->dt0+v->drive, v->elem, v->rot)) {
  789. qunlock(v);
  790. return 0;
  791. }
  792. v->status = Sunload;
  793. }
  794. qunlock(v);
  795. }
  796. j += w->nse;
  797. if(j < w->nside) {
  798. v = &w->side[j];
  799. qlock(v);
  800. if(v->status == Sstart) {
  801. if(mmove(w, w->mt0, w->dt0+v->drive, v->elem, v->rot)) {
  802. qunlock(v);
  803. return 0;
  804. }
  805. v->status = Sunload;
  806. }
  807. qunlock(v);
  808. }
  809. v = &w->side[i];
  810. qlock(v);
  811. return v;
  812. }
  813. static
  814. void
  815. cmd_wormoffline(int argc, char *argv[])
  816. {
  817. int u, i;
  818. Juke *w;
  819. if(argc <= 1) {
  820. print("usage: wormoffline drive\n");
  821. return;
  822. }
  823. u = number(argv[1], -1, 10);
  824. w = jukelist;
  825. if(u < 0 || u >= w->ndrive) {
  826. print("bad drive %s (0<=%d<%d)\n", argv[1], u, w->ndrive);
  827. return;
  828. }
  829. if(w->offline[u])
  830. print("drive %d already offline\n", u);
  831. w->offline[u] = 1;
  832. for(i=0; i<w->ndrive; i++)
  833. if(w->offline[i] == 0)
  834. return;
  835. print("that would take all drives offline\n");
  836. w->offline[u] = 0;
  837. }
  838. static
  839. void
  840. cmd_wormonline(int argc, char *argv[])
  841. {
  842. int u;
  843. Juke *w;
  844. if(argc <= 1) {
  845. print("usage: wormonline drive\n");
  846. return;
  847. }
  848. u = number(argv[1], -1, 10);
  849. w = jukelist;
  850. if(u < 0 || u >= w->ndrive) {
  851. print("bad drive %s (0<=%d<%d)\n", argv[1], u, w->ndrive);
  852. return;
  853. }
  854. if(w->offline[u] == 0)
  855. print("drive %d already online\n", u);
  856. w->offline[u] = 0;
  857. }
  858. static
  859. void
  860. cmd_wormreset(int, char *[])
  861. {
  862. Juke *w;
  863. for(w=jukelist; w; w=w->link) {
  864. qlock(w);
  865. positions(w);
  866. qunlock(w);
  867. }
  868. }
  869. static
  870. void
  871. cmd_wormeject(int argc, char *argv[])
  872. {
  873. Juke *w;
  874. Side *v;
  875. if(argc <= 1) {
  876. print("usage: wormeject unit\n");
  877. return;
  878. }
  879. v = wormi(argv[1]);
  880. if(v == 0)
  881. return;
  882. w = jukelist;
  883. mmove(w, w->mt0, v->elem, w->ie0, 0);
  884. qunlock(v);
  885. }
  886. static
  887. void
  888. cmd_wormingest(int argc, char *argv[])
  889. {
  890. Juke *w;
  891. Side *v;
  892. if(argc <= 1) {
  893. print("usage: wormingest unit\n");
  894. return;
  895. }
  896. v = wormi(argv[1]);
  897. if(v == 0)
  898. return;
  899. w = jukelist;
  900. mmove(w, w->mt0, w->ie0, v->elem, 0);
  901. qunlock(v);
  902. }
  903. void
  904. jukeinit(Device *d)
  905. {
  906. Juke *w;
  907. Device *xdev;
  908. Side *v;
  909. int i;
  910. /* j(w<changer>w<station0>...)(r<platters>) */
  911. xdev = d->j.j;
  912. if(xdev->type != Devmcat) {
  913. print("juke union not mcat\n");
  914. goto bad;
  915. }
  916. /*
  917. * pick up the changer device
  918. */
  919. xdev = xdev->cat.first;
  920. if(xdev->type != Devwren) {
  921. print("juke changer not wren %Z\n", xdev);
  922. goto bad;
  923. }
  924. for(w=jukelist; w; w=w->link)
  925. if(xdev == w->juke)
  926. goto found;
  927. /*
  928. * allocate a juke structure
  929. * no locking problems.
  930. */
  931. w = ialloc(sizeof(Juke), 0);
  932. w->link = jukelist;
  933. jukelist = w;
  934. print("alloc juke %Z\n", xdev);
  935. qlock(w);
  936. qunlock(w);
  937. w->name = "juke";
  938. w->juke = xdev;
  939. geometry(w);
  940. /*
  941. * pick up each side
  942. */
  943. w->nside = w->nse;
  944. if(w->rot)
  945. w->nside += w->nside;
  946. if(w->nside > MAXSIDE) {
  947. print("too many sides: %d max %d\n", w->nside, MAXSIDE);
  948. goto bad;
  949. }
  950. for(i=0; i<w->nse; i++) {
  951. v = &w->side[i];
  952. qlock(v);
  953. qunlock(v);
  954. v->name = "shelf";
  955. v->elem = w->se0 + i;
  956. v->rot = 0;
  957. v->status = Sempty;
  958. v->time = toytime();
  959. if(w->rot) {
  960. v += w->nse;
  961. qlock(v);
  962. qunlock(v);
  963. v->name = "shelf";
  964. v->elem = w->se0 + i;
  965. v->rot = 1;
  966. v->status = Sempty;
  967. v->time = toytime();
  968. }
  969. }
  970. positions(w);
  971. w->ndrive = w->ndt;
  972. if(w->ndrive > MAXDRIVE) {
  973. print("ndrives truncated to %d\n", MAXDRIVE);
  974. w->ndrive = MAXDRIVE;
  975. }
  976. /*
  977. * pick up each drive
  978. */
  979. for(i=0; i<w->ndrive; i++)
  980. w->drive[i] = devnone;
  981. cmd_install("wormreset", "-- put drives back where jukebox thinks they belong", cmd_wormreset);
  982. cmd_install("wormeject", "unit -- shelf to outside", cmd_wormeject);
  983. cmd_install("wormingest", "unit -- outside to shelf", cmd_wormingest);
  984. cmd_install("wormoffline", "unit -- disable drive", cmd_wormoffline);
  985. cmd_install("wormonline", "unit -- enable drive", cmd_wormonline);
  986. found:
  987. i = 0;
  988. while(xdev = xdev->link) {
  989. if(xdev->type != Devwren) {
  990. print("drive not devwren: %Z\n", xdev);
  991. goto bad;
  992. }
  993. if(w->drive[i]->type != Devnone &&
  994. xdev != w->drive[i]) {
  995. print("double init drive %d %Z %Z\n", i, w->drive[i], xdev);
  996. goto bad;
  997. }
  998. if(i >= w->ndrive) {
  999. print("too many drives %Z\n", xdev);
  1000. goto bad;
  1001. }
  1002. w->drive[i++] = xdev;
  1003. }
  1004. if(i <= 0) {
  1005. print("no drives\n");
  1006. goto bad;
  1007. }
  1008. /*
  1009. * put w pointer in each platter
  1010. */
  1011. d->private = w;
  1012. jinit(w, d->j.m, 0);
  1013. w->probeok = 1;
  1014. return;
  1015. bad:
  1016. panic("juke init");
  1017. }
  1018. /*
  1019. * called periodically
  1020. */
  1021. void
  1022. wormprobe(void)
  1023. {
  1024. int i, drive;
  1025. Timet t;
  1026. Side *v;
  1027. Juke *w;
  1028. t = toytime() - TWORM;
  1029. for(w=jukelist; w; w=w->link) {
  1030. if(w->probeok == 0 || !canqlock(w))
  1031. continue;
  1032. for(i=0; i<w->nside; i++) {
  1033. v = &w->side[i];
  1034. if(!canqlock(v))
  1035. continue;
  1036. if(v->status == Sstart && t > v->time) {
  1037. drive = v->drive;
  1038. print(" time r%ld drive %Z\n",
  1039. v-w->side, w->drive[drive]);
  1040. mmove(w, w->mt0, w->dt0+drive, v->elem, v->rot);
  1041. v->status = Sunload;
  1042. }
  1043. qunlock(v);
  1044. }
  1045. qunlock(w);
  1046. }
  1047. }