juke.c 28 KB

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