juke.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328
  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 (seek(dr->wren.fd, (vlong)b*RBUFSIZE, 0) < 0 ||
  610. read(dr->wren.fd, c, RBUFSIZE) != RBUFSIZE) {
  611. fd2path(dr->wren.fd, name, sizeof name);
  612. print("wormread: error on %Z(%lld) on %s in %s: %r\n",
  613. d, (Wideoff)b, name, dr->wren.sddir);
  614. cons.nwormre++;
  615. r = 1;
  616. }
  617. qunlock(v);
  618. return r;
  619. }
  620. int
  621. wormwrite(Device *d, Off b, void *c)
  622. {
  623. int r = 0;
  624. long max;
  625. char name[128];
  626. Side *v = wormunit(d);
  627. Juke *w = d->private;
  628. Device *dr;
  629. if (v == nil)
  630. panic("wormwrite: nil wormunit(%Z)", d);
  631. dr = w->drive[v->drive];
  632. if (dr->wren.fd < 0)
  633. panic("wormwrite: unopened fd for %Z", d);
  634. max = (d->type == Devlworm? v->max + 1: v->max);
  635. if(b >= max) {
  636. print("wormwrite: block out of range %Z(%lld)\n",
  637. d, (Wideoff)b);
  638. r = 0x071;
  639. } else if (seek(dr->wren.fd, (vlong)b*RBUFSIZE, 0) < 0 ||
  640. write(dr->wren.fd, c, RBUFSIZE) != RBUFSIZE) {
  641. fd2path(dr->wren.fd, name, sizeof name);
  642. print("wormwrwite: error on %Z(%lld) on %s in %s: %r\n",
  643. d, (Wideoff)b, name, dr->wren.sddir);
  644. cons.nwormwe++;
  645. r = 1;
  646. }
  647. qunlock(v);
  648. return r;
  649. }
  650. static int
  651. mmove(Juke *w, int trans, int from, int to, int rot)
  652. {
  653. int s;
  654. uchar cmd[12], buf[4];
  655. static int recur = 0;
  656. memset(cmd, 0, sizeof cmd);
  657. cmd[0] = 0xa5; /* move medium */
  658. cmd[2] = trans>>8;
  659. cmd[3] = trans;
  660. cmd[4] = from>>8;
  661. cmd[5] = from;
  662. cmd[6] = to>>8;
  663. cmd[7] = to;
  664. if(rot)
  665. cmd[10] = 1;
  666. s = scsiio(w->juke, SCSInone, cmd, sizeof cmd, buf, 0); /* mmove */
  667. if(s) {
  668. print("scsio status #%x\n", s);
  669. print("move medium t=%d fr=%d to=%d rot=%d\n",
  670. trans, from, to, rot);
  671. // panic("mmove");
  672. if(recur == 0) {
  673. recur = 1;
  674. print("element from=%d\n", from);
  675. element(w, from);
  676. print("element to=%d\n", to);
  677. element(w, to);
  678. print("element trans=%d\n", trans);
  679. element(w, trans);
  680. recur = 0;
  681. }
  682. return 1;
  683. }
  684. return 0;
  685. }
  686. static void
  687. geometry(Juke *w)
  688. {
  689. int s;
  690. uchar cmd[6], buf[4+20];
  691. memset(cmd, 0, sizeof cmd);
  692. memset(buf, 0, sizeof buf);
  693. cmd[0] = 0x1a; /* mode sense */
  694. cmd[2] = 0x1d; /* element address assignment */
  695. cmd[4] = sizeof buf; /* allocation length */
  696. s = scsiio(w->juke, SCSIread, cmd, sizeof cmd, buf, sizeof buf); /* mode sense elem addrs */
  697. if(s)
  698. panic("geometry #%x", s);
  699. w->mt0 = (buf[4+2]<<8) | buf[4+3];
  700. w->nmt = (buf[4+4]<<8) | buf[4+5];
  701. w->se0 = (buf[4+6]<<8) | buf[4+7];
  702. w->nse = (buf[4+8]<<8) | buf[4+9];
  703. w->ie0 = (buf[4+10]<<8) | buf[4+11];
  704. w->nie = (buf[4+12]<<8) | buf[4+13];
  705. w->dt0 = (buf[4+14]<<8) | buf[4+15];
  706. w->ndt = (buf[4+16]<<8) | buf[4+17];
  707. memset(cmd, 0, 6);
  708. memset(buf, 0, sizeof buf);
  709. cmd[0] = 0x1a; /* mode sense */
  710. cmd[2] = 0x1e; /* transport geometry */
  711. cmd[4] = sizeof buf; /* allocation length */
  712. s = scsiio(w->juke, SCSIread, cmd, sizeof cmd, buf, sizeof buf); /* mode sense geometry */
  713. if(s)
  714. panic("geometry #%x", s);
  715. w->rot = buf[4+2] & 1;
  716. print("\tmt %d %d\n", w->mt0, w->nmt);
  717. print("\tse %d %d\n", w->se0, w->nse);
  718. print("\tie %d %d\n", w->ie0, w->nie);
  719. print("\tdt %d %d\n", w->dt0, w->ndt);
  720. print("\trot %d\n", w->rot);
  721. prflush();
  722. }
  723. /*
  724. * read element e's status from jukebox w, move any disc in drive back to its
  725. * slot, and update and print software status.
  726. */
  727. static void
  728. element(Juke *w, int e)
  729. {
  730. uchar cmd[12], buf[8+8+88];
  731. int s, t;
  732. memset(cmd, 0, sizeof cmd);
  733. memset(buf, 0, sizeof buf);
  734. cmd[0] = 0xb8; /* read element status */
  735. cmd[2] = e>>8; /* starting element */
  736. cmd[3] = e;
  737. cmd[5] = 1; /* number of elements */
  738. cmd[9] = sizeof buf; /* allocation length */
  739. s = scsiio(w->juke, SCSIread, cmd, sizeof cmd, buf, sizeof buf); /* read elem sts */
  740. if(s) {
  741. print("scsiio #%x\n", s);
  742. goto bad;
  743. }
  744. s = (buf[0]<<8) | buf[1];
  745. if(s != e) {
  746. print("element = %d\n", s);
  747. goto bad;
  748. }
  749. if(buf[3] != 1) {
  750. print("number reported = %d\n", buf[3]);
  751. goto bad;
  752. }
  753. s = (buf[8+8+0]<<8) | buf[8+8+1];
  754. if(s != e) {
  755. print("element1 = %d\n", s);
  756. goto bad;
  757. }
  758. switch(buf[8+0]) { /* element type */
  759. default:
  760. print("unknown element %d: %d\n", e, buf[8+0]);
  761. goto bad;
  762. case 1: /* transport */
  763. s = e - w->mt0;
  764. if(s < 0 || s >= w->nmt)
  765. goto bad;
  766. if(buf[8+8+2] & 1)
  767. print("transport %d full %d.%d\n", s,
  768. (buf[8+8+10]<<8) | buf[8+8+11],
  769. (buf[8+8+9]>>6) & 1);
  770. break;
  771. case 2: /* storage */
  772. s = e - w->se0;
  773. if(s < 0 || s >= w->nse)
  774. goto bad;
  775. w->side[s].status = Sempty;
  776. if(buf[8+8+2] & 1)
  777. w->side[s].status = Sunload;
  778. if(w->rot)
  779. w->side[w->nse+s].status = w->side[s].status;
  780. break;
  781. case 3: /* import/export */
  782. s = e - w->ie0;
  783. if(s < 0 || s >= w->nie)
  784. goto bad;
  785. print("import/export %d #%.2x %d.%d\n", s,
  786. buf[8+8+2],
  787. (buf[8+8+10]<<8) | buf[8+8+11],
  788. (buf[8+8+9]>>6) & 1);
  789. break;
  790. case 4: /* data transfer */
  791. s = e - w->dt0;
  792. if(s < 0 || s >= w->ndt)
  793. goto bad;
  794. print("data transfer %d #%.2x %d.%d\n", s,
  795. buf[8+8+2],
  796. (buf[8+8+10]<<8) | buf[8+8+11],
  797. (buf[8+8+9]>>6) & 1);
  798. if(buf[8+8+2] & 1) {
  799. t = ((buf[8+8+10]<<8) | buf[8+8+11]) - w->se0;
  800. if (t < 0 || t >= w->nse || t >= MAXSIDE ||
  801. s >= MAXDRIVE) {
  802. print(
  803. "element: juke %Z lies; claims side %d is in drive %d\n",
  804. w->juke, t, s); /* lying sack of ... */
  805. /*
  806. * at minimum, we've avoided corrupting our
  807. * data structures. if we know that numbers
  808. * like w->nside are valid here, we could use
  809. * them in more stringent tests.
  810. * perhaps should whack the jukebox upside the
  811. * head here to knock some sense into it.
  812. */
  813. goto bad;
  814. }
  815. print("r%d in drive %d\n", t, s);
  816. if(mmove(w, w->mt0, w->dt0+s, w->se0+t,
  817. (buf[8+8+9]>>6) & 1)) {
  818. print("mmove initial unload\n");
  819. goto bad;
  820. }
  821. w->side[t].status = Sunload;
  822. if(w->rot)
  823. w->side[w->nse+t].status = Sunload;
  824. }
  825. if(buf[8+8+2] & 4) {
  826. print("drive w%d has exception #%.2x #%.2x\n", s,
  827. buf[8+8+4], buf[8+8+5]);
  828. goto bad;
  829. }
  830. break;
  831. }
  832. return;
  833. bad:
  834. /* panic("element") */ ;
  835. }
  836. /*
  837. * read all elements' status from jukebox w, move any discs in drives back
  838. * to their slots, and update and print software status.
  839. */
  840. static void
  841. positions(Juke *w)
  842. {
  843. int i, f;
  844. /* mark empty shelves */
  845. for(i=0; i<w->nse; i++)
  846. element(w, w->se0+i);
  847. for(i=0; i<w->nmt; i++)
  848. element(w, w->mt0+i);
  849. for(i=0; i<w->nie; i++)
  850. element(w, w->ie0+i);
  851. for(i=0; i<w->ndt; i++)
  852. element(w, w->dt0+i);
  853. f = 0;
  854. for(i=0; i<w->nse; i++)
  855. if(w->side[i].status == Sempty) {
  856. if(f) {
  857. print("r%d\n", i-1);
  858. f = 0;
  859. }
  860. } else {
  861. if(!f) {
  862. print("\tshelves r%d-", i);
  863. f = 1;
  864. }
  865. }
  866. if(f)
  867. print("r%d\n", i-1);
  868. }
  869. static void
  870. jinit(Juke *w, Device *d, int o)
  871. {
  872. int p;
  873. Device *dev = d;
  874. switch(d->type) {
  875. default:
  876. print("juke platter not (devmcat of) dev(l)worm: %Z\n", d);
  877. panic("jinit: type");
  878. case Devmcat:
  879. /*
  880. * we don't call mcatinit(d) here, so we have to set d->cat.ndev
  881. * ourselves.
  882. */
  883. for(d=d->cat.first; d; d=d->link)
  884. jinit(w, d, o++);
  885. dev->cat.ndev = o;
  886. break;
  887. case Devlworm:
  888. p = d->wren.targ;
  889. if(p < 0 || p >= w->nside)
  890. panic("jinit partition %Z", d);
  891. w->side[p].ord = o;
  892. /* FALL THROUGH */
  893. case Devworm:
  894. if(d->private) {
  895. print("juke platter private pointer set %p\n",
  896. d->private);
  897. panic("jinit: private");
  898. }
  899. d->private = w;
  900. break;
  901. }
  902. }
  903. Side*
  904. wormi(char *arg)
  905. {
  906. int i, j;
  907. Juke *w;
  908. Side *v;
  909. i = number(arg, -1, 10) - 1;
  910. w = jukelist;
  911. if(i < 0 || i >= w->nside) {
  912. print("bad unit number %s (%d)\n", arg, i+1);
  913. return 0;
  914. }
  915. j = i;
  916. if(j >= w->nse)
  917. j -= w->nse;
  918. if(j < w->nside) {
  919. v = &w->side[j];
  920. qlock(v);
  921. if(v->status == Sstart) {
  922. if(mmove(w, w->mt0, w->dt0+v->drive, v->elem, v->rot)) {
  923. qunlock(v);
  924. return 0;
  925. }
  926. v->status = Sunload;
  927. }
  928. qunlock(v);
  929. }
  930. j += w->nse;
  931. if(j < w->nside) {
  932. v = &w->side[j];
  933. qlock(v);
  934. if(v->status == Sstart) {
  935. if(mmove(w, w->mt0, w->dt0+v->drive, v->elem, v->rot)) {
  936. qunlock(v);
  937. return 0;
  938. }
  939. v->status = Sunload;
  940. }
  941. qunlock(v);
  942. }
  943. v = &w->side[i];
  944. qlock(v);
  945. return v;
  946. }
  947. static void
  948. cmd_wormoffline(int argc, char *argv[])
  949. {
  950. int u, i;
  951. Juke *w;
  952. if(argc <= 1) {
  953. print("usage: wormoffline drive\n");
  954. return;
  955. }
  956. u = number(argv[1], -1, 10);
  957. w = jukelist;
  958. if(u < 0 || u >= w->ndrive) {
  959. print("bad drive %s (0<=%d<%d)\n", argv[1], u, w->ndrive);
  960. return;
  961. }
  962. if(w->offline[u])
  963. print("drive %d already offline\n", u);
  964. w->offline[u] = 1;
  965. for(i=0; i<w->ndrive; i++)
  966. if(w->offline[i] == 0)
  967. return;
  968. print("that would take all drives offline\n");
  969. w->offline[u] = 0;
  970. }
  971. static void
  972. cmd_wormonline(int argc, char *argv[])
  973. {
  974. int u;
  975. Juke *w;
  976. if(argc <= 1) {
  977. print("usage: wormonline drive\n");
  978. return;
  979. }
  980. u = number(argv[1], -1, 10);
  981. w = jukelist;
  982. if(u < 0 || u >= w->ndrive) {
  983. print("bad drive %s (0<=%d<%d)\n", argv[1], u, w->ndrive);
  984. return;
  985. }
  986. if(w->offline[u] == 0)
  987. print("drive %d already online\n", u);
  988. w->offline[u] = 0;
  989. }
  990. void
  991. cmd_wormreset(int, char *[])
  992. {
  993. Juke *w;
  994. for(w=jukelist; w; w=w->link) {
  995. qlock(w);
  996. positions(w);
  997. qunlock(w);
  998. }
  999. }
  1000. static void
  1001. cmd_wormeject(int argc, char *argv[])
  1002. {
  1003. Juke *w;
  1004. Side *v;
  1005. if(argc <= 1) {
  1006. print("usage: wormeject unit\n");
  1007. return;
  1008. }
  1009. v = wormi(argv[1]);
  1010. if(v == 0)
  1011. return;
  1012. w = jukelist;
  1013. mmove(w, w->mt0, v->elem, w->ie0, 0);
  1014. qunlock(v);
  1015. }
  1016. static void
  1017. cmd_wormingest(int argc, char *argv[])
  1018. {
  1019. Juke *w;
  1020. Side *v;
  1021. if(argc <= 1) {
  1022. print("usage: wormingest unit\n");
  1023. return;
  1024. }
  1025. v = wormi(argv[1]);
  1026. if(v == 0)
  1027. return;
  1028. w = jukelist;
  1029. mmove(w, w->mt0, w->ie0, v->elem, 0);
  1030. qunlock(v);
  1031. }
  1032. static void
  1033. newside(Side *v, int rot, int elem)
  1034. {
  1035. qlock(v);
  1036. qunlock(v);
  1037. // v->name = "shelf";
  1038. v->elem = elem;
  1039. v->rot = rot;
  1040. v->status = Sempty;
  1041. v->time = toytime();
  1042. }
  1043. /*
  1044. * query jukebox robotics for geometry;
  1045. * argument is the wren dev of the changer.
  1046. * result is actually Juke*, but that type is only known in this file.
  1047. */
  1048. void *
  1049. querychanger(Device *xdev)
  1050. {
  1051. Juke *w;
  1052. Side *v;
  1053. int i;
  1054. if (xdev == nil)
  1055. panic("querychanger: nil Device");
  1056. if(xdev->type != Devwren) {
  1057. print("juke changer not wren %Z\n", xdev);
  1058. goto bad;
  1059. }
  1060. for(w=jukelist; w; w=w->link)
  1061. if(xdev == w->juke)
  1062. return w;
  1063. /*
  1064. * allocate a juke structure
  1065. * no locking problems.
  1066. */
  1067. w = malloc(sizeof(Juke));
  1068. w->magic = Jukemagic;
  1069. w->isfixedsize = FIXEDSIZE;
  1070. w->link = jukelist;
  1071. jukelist = w;
  1072. print("alloc juke %Z\n", xdev);
  1073. qlock(w);
  1074. qunlock(w);
  1075. // w->name = "juke";
  1076. w->juke = xdev;
  1077. w->robotdir = sdof(xdev);
  1078. w->robot = openscsi(w->robotdir);
  1079. if (w->robot == nil)
  1080. panic("can't openscsi(%s): %r", w->robotdir);
  1081. newscsi(xdev, w->robot);
  1082. geometry(w);
  1083. /*
  1084. * pick up each side
  1085. */
  1086. w->nside = w->nse;
  1087. if(w->rot)
  1088. w->nside += w->nside;
  1089. if(w->nside > MAXSIDE) {
  1090. print("too many sides: %d max %d\n", w->nside, MAXSIDE);
  1091. goto bad;
  1092. }
  1093. for(i=0; i < w->nse; i++) {
  1094. v = &w->side[i];
  1095. newside(v, 0, w->se0 + i);
  1096. if(w->rot)
  1097. newside(v + w->nse, 1, w->se0 + i);
  1098. }
  1099. positions(w);
  1100. w->ndrive = w->ndt;
  1101. if(w->ndrive > MAXDRIVE) {
  1102. print("ndrives truncated to %d\n", MAXDRIVE);
  1103. w->ndrive = MAXDRIVE;
  1104. }
  1105. /*
  1106. * pick up each drive
  1107. */
  1108. for(i=0; i<w->ndrive; i++)
  1109. w->drive[i] = devnone;
  1110. return w;
  1111. bad:
  1112. panic("querychanger: %Z", xdev);
  1113. return nil;
  1114. }
  1115. void
  1116. jukeinit(Device *d)
  1117. {
  1118. Juke *w;
  1119. Device *xdev;
  1120. int i;
  1121. static int beenhere = 0;
  1122. /* j(w<changer>w<station0>...)(r<platters>) */
  1123. if (d == nil)
  1124. panic("jukeinit: nil Device");
  1125. xdev = d->j.j;
  1126. if(xdev == nil || xdev->type != Devmcat) {
  1127. print("juke union not mcat\n");
  1128. goto bad;
  1129. }
  1130. /*
  1131. * pick up the changer device
  1132. */
  1133. xdev = xdev->cat.first;
  1134. w = querychanger(xdev);
  1135. if (!beenhere) {
  1136. beenhere = 1;
  1137. cmd_install("wormreset",
  1138. "-- put drives back where jukebox thinks they belong",
  1139. cmd_wormreset);
  1140. cmd_install("wormeject", "unit -- shelf to outside",
  1141. cmd_wormeject);
  1142. cmd_install("wormingest", "unit -- outside to shelf",
  1143. cmd_wormingest);
  1144. cmd_install("wormoffline", "unit -- disable drive",
  1145. cmd_wormoffline);
  1146. cmd_install("wormonline", "unit -- enable drive",
  1147. cmd_wormonline);
  1148. }
  1149. /* walk through the worm drives */
  1150. i = 0;
  1151. while(xdev = xdev->link) {
  1152. if(xdev->type != Devwren) {
  1153. print("drive not devwren: %Z\n", xdev);
  1154. goto bad;
  1155. }
  1156. if(w->drive[i]->type != Devnone &&
  1157. xdev != w->drive[i]) {
  1158. print("double init drive %d %Z %Z\n",
  1159. i, w->drive[i], xdev);
  1160. goto bad;
  1161. }
  1162. if(i >= w->ndrive) {
  1163. print("too many drives %Z\n", xdev);
  1164. goto bad;
  1165. }
  1166. w->drive[i++] = xdev;
  1167. }
  1168. if(i <= 0) {
  1169. print("no drives\n");
  1170. goto bad;
  1171. }
  1172. /*
  1173. * put w pointer in each platter
  1174. */
  1175. d->private = w;
  1176. jinit(w, d->j.m, 0);
  1177. w->probeok = 1;
  1178. return;
  1179. bad:
  1180. panic("juke init");
  1181. }
  1182. /*
  1183. * called periodically
  1184. */
  1185. void
  1186. wormprobe(void)
  1187. {
  1188. int i, drive;
  1189. Timet t;
  1190. Side *v;
  1191. Juke *w;
  1192. t = toytime() - TWORM;
  1193. for(w=jukelist; w; w=w->link) {
  1194. if(w->probeok == 0 || !canqlock(w))
  1195. continue;
  1196. for(i=0; i<w->nside; i++) {
  1197. v = &w->side[i];
  1198. if(!canqlock(v))
  1199. continue;
  1200. if(v->status == Sstart && t > v->time) {
  1201. drive = v->drive;
  1202. print("\ttime r%ld drive %Z\n",
  1203. v-w->side, w->drive[drive]);
  1204. mmove(w, w->mt0, w->dt0+drive, v->elem, v->rot);
  1205. v->status = Sunload;
  1206. }
  1207. qunlock(v);
  1208. }
  1209. qunlock(w);
  1210. }
  1211. }