juke.c 29 KB

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