juke.c 28 KB

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