scuzz.c 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "scsireq.h"
  5. #define MIN(a, b) ((a) < (b) ? (a): (b))
  6. static char rwbuf[MaxIOsize];
  7. static int verbose = 1;
  8. Biobuf bin, bout;
  9. long maxiosize = MaxIOsize;
  10. int exabyte = 0;
  11. int force6bytecmds = 0;
  12. typedef struct {
  13. char *name;
  14. long (*f)(ScsiReq *, int, char *[]);
  15. int open;
  16. char *help;
  17. } ScsiCmd;
  18. static ScsiCmd scsicmd[];
  19. static vlong
  20. vlmin(vlong a, vlong b)
  21. {
  22. if (a < b)
  23. return a;
  24. else
  25. return b;
  26. }
  27. static long
  28. cmdready(ScsiReq *rp, int argc, char *argv[])
  29. {
  30. USED(argc, argv);
  31. return SRready(rp);
  32. }
  33. static long
  34. cmdrewind(ScsiReq *rp, int argc, char *argv[])
  35. {
  36. USED(argc, argv);
  37. return SRrewind(rp);
  38. }
  39. static long
  40. cmdreqsense(ScsiReq *rp, int argc, char *argv[])
  41. {
  42. long nbytes;
  43. USED(argc, argv);
  44. if((nbytes = SRreqsense(rp)) != -1)
  45. makesense(rp);
  46. return nbytes;
  47. }
  48. static long
  49. cmdformat(ScsiReq *rp, int argc, char *argv[])
  50. {
  51. USED(argc, argv);
  52. return SRformat(rp);
  53. }
  54. static long
  55. cmdrblimits(ScsiReq *rp, int argc, char *argv[])
  56. {
  57. uchar l[6];
  58. long n;
  59. USED(argc, argv);
  60. if((n = SRrblimits(rp, l)) == -1)
  61. return -1;
  62. Bprint(&bout, " %2.2uX %2.2uX %2.2uX %2.2uX %2.2uX %2.2uX\n",
  63. l[0], l[1], l[2], l[3], l[4], l[5]);
  64. return n;
  65. }
  66. static int
  67. mkfile(char *file, int omode, int *pid)
  68. {
  69. int fd[2];
  70. if(*file != '|'){
  71. *pid = -1;
  72. if(omode == OWRITE)
  73. return create(file, OWRITE, 0666);
  74. else if(omode == OREAD)
  75. return open(file, OREAD);
  76. return -1;
  77. }
  78. file++;
  79. if(*file == 0 || pipe(fd) == -1)
  80. return -1;
  81. if((*pid = fork()) == -1){
  82. close(fd[0]);
  83. close(fd[1]);
  84. return -1;
  85. }
  86. if(*pid == 0){
  87. switch(omode){
  88. case OREAD:
  89. dup(fd[0], 1);
  90. break;
  91. case OWRITE:
  92. dup(fd[0], 0);
  93. break;
  94. }
  95. close(fd[0]);
  96. close(fd[1]);
  97. execl("/bin/rc", "rc", "-c", file, nil);
  98. exits("exec");
  99. }
  100. close(fd[0]);
  101. return fd[1];
  102. }
  103. int
  104. waitfor(int pid)
  105. {
  106. int msg;
  107. Waitmsg *w;
  108. while((w = wait()) != nil){
  109. if(w->pid != pid){
  110. free(w);
  111. continue;
  112. }
  113. msg = (w->msg[0] != '\0');
  114. free(w);
  115. return msg;
  116. }
  117. return -1;
  118. }
  119. static long
  120. cmdread(ScsiReq *rp, int argc, char *argv[])
  121. {
  122. long n, iosize, prevsize = 0;
  123. vlong nbytes, total;
  124. int fd, pid;
  125. char *p;
  126. iosize = maxiosize;
  127. nbytes = ~0ULL >> 1;
  128. switch(argc){
  129. default:
  130. rp->status = Status_BADARG;
  131. return -1;
  132. case 2:
  133. nbytes = strtoll(argv[1], &p, 0);
  134. if(nbytes == 0 && p == argv[1]){
  135. rp->status = Status_BADARG;
  136. return -1;
  137. }
  138. /*FALLTHROUGH*/
  139. case 1:
  140. if((fd = mkfile(argv[0], OWRITE, &pid)) == -1){
  141. rp->status = Status_BADARG;
  142. return -1;
  143. }
  144. break;
  145. }
  146. print("bsize=%lud\n", rp->lbsize);
  147. total = 0;
  148. while(nbytes){
  149. n = vlmin(nbytes, iosize);
  150. if((n = SRread(rp, rwbuf, n)) == -1){
  151. if(total == 0)
  152. total = -1;
  153. break;
  154. }
  155. if (n == 0)
  156. break;
  157. if (prevsize != n) {
  158. print("tape block size=%ld\n", n);
  159. prevsize = n;
  160. }
  161. if(write(fd, rwbuf, n) != n){
  162. if(total == 0)
  163. total = -1;
  164. if(rp->status == STok)
  165. rp->status = Status_SW;
  166. break;
  167. }
  168. nbytes -= n;
  169. total += n;
  170. }
  171. close(fd);
  172. if(pid >= 0 && waitfor(pid)){
  173. rp->status = Status_SW;
  174. return -1;
  175. }
  176. return total;
  177. }
  178. static long
  179. cmdwrite(ScsiReq *rp, int argc, char *argv[])
  180. {
  181. long n, prevsize = 0;
  182. vlong nbytes, total;
  183. int fd, pid;
  184. char *p;
  185. nbytes = ~0ULL >> 1;
  186. switch(argc){
  187. default:
  188. rp->status = Status_BADARG;
  189. return -1;
  190. case 2:
  191. nbytes = strtoll(argv[1], &p, 0);
  192. if(nbytes == 0 && p == argv[1]){
  193. rp->status = Status_BADARG;
  194. return -1;
  195. }
  196. /*FALLTHROUGH*/
  197. case 1:
  198. if((fd = mkfile(argv[0], OREAD, &pid)) == -1){
  199. rp->status = Status_BADARG;
  200. return -1;
  201. }
  202. break;
  203. }
  204. total = 0;
  205. while(nbytes){
  206. n = vlmin(nbytes, maxiosize);
  207. if((n = read(fd, rwbuf, n)) == -1){
  208. if(total == 0)
  209. total = -1;
  210. break;
  211. }
  212. if (n == 0)
  213. break;
  214. if (prevsize != n) {
  215. print("tape block size=%ld\n", n);
  216. prevsize = n;
  217. }
  218. if(SRwrite(rp, rwbuf, n) != n){
  219. if(total == 0)
  220. total = -1;
  221. if(rp->status == STok)
  222. rp->status = Status_SW;
  223. break;
  224. }
  225. nbytes -= n;
  226. total += n;
  227. }
  228. close(fd);
  229. if(pid >= 0 && waitfor(pid)){
  230. rp->status = Status_SW;
  231. return -1;
  232. }
  233. return total;
  234. }
  235. static long
  236. cmdseek(ScsiReq *rp, int argc, char *argv[])
  237. {
  238. char *p;
  239. long offset;
  240. int type;
  241. type = 0;
  242. switch(argc){
  243. default:
  244. rp->status = Status_BADARG;
  245. return -1;
  246. case 2:
  247. if((type = strtol(argv[1], &p, 0)) == 0 && p == argv[1]){
  248. rp->status = Status_BADARG;
  249. return -1;
  250. }
  251. /*FALLTHROUGH*/
  252. case 1:
  253. if((offset = strtol(argv[0], &p, 0)) == 0 && p == argv[0]){
  254. rp->status = Status_BADARG;
  255. return -1;
  256. }
  257. break;
  258. }
  259. return SRseek(rp, offset, type);
  260. }
  261. static long
  262. cmdfilemark(ScsiReq *rp, int argc, char *argv[])
  263. {
  264. char *p;
  265. ulong howmany;
  266. howmany = 1;
  267. if(argc && (howmany = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
  268. rp->status = Status_BADARG;
  269. return -1;
  270. }
  271. return SRfilemark(rp, howmany);
  272. }
  273. static long
  274. cmdspace(ScsiReq *rp, int argc, char *argv[])
  275. {
  276. uchar code;
  277. long howmany;
  278. char option, *p;
  279. code = 0x00;
  280. howmany = 1;
  281. while(argc && (*argv)[0] == '-'){
  282. while(option = *++argv[0]){
  283. switch(option){
  284. case '-':
  285. break;
  286. case 'b':
  287. code = 0x00;
  288. break;
  289. case 'f':
  290. code = 0x01;
  291. break;
  292. default:
  293. rp->status = Status_BADARG;
  294. return -1;
  295. }
  296. break;
  297. }
  298. argc--; argv++;
  299. if(option == '-')
  300. break;
  301. }
  302. if(argc && ((howmany = strtol(argv[0], &p, 0)) == 0 && p == argv[0])){
  303. rp->status = Status_BADARG;
  304. return -1;
  305. }
  306. return SRspace(rp, code, howmany);
  307. }
  308. static long
  309. cmdinquiry(ScsiReq *rp, int argc, char *argv[])
  310. {
  311. long status;
  312. int i, n;
  313. uchar *p;
  314. USED(argc, argv);
  315. if((status = SRinquiry(rp)) != -1){
  316. n = rp->inquiry[4]+4;
  317. for(i = 0; i < MIN(8, n); i++)
  318. Bprint(&bout, " %2.2uX", rp->inquiry[i]);
  319. p = &rp->inquiry[8];
  320. n = MIN(n, sizeof(rp->inquiry)-8);
  321. while(n && (*p == ' ' || *p == '\t' || *p == '\n')){
  322. n--;
  323. p++;
  324. }
  325. Bprint(&bout, "\t%.*s\n", n, (char*)p);
  326. }
  327. return status;
  328. }
  329. static long
  330. cmdmodeselect6(ScsiReq *rp, int argc, char *argv[])
  331. {
  332. uchar list[MaxDirData];
  333. long nbytes, ul;
  334. char *p;
  335. memset(list, 0, sizeof list);
  336. for(nbytes = 0; argc; argc--, argv++, nbytes++){
  337. if((ul = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
  338. rp->status = Status_BADARG;
  339. return -1;
  340. }
  341. list[nbytes] = ul;
  342. }
  343. if(!(rp->flags & Finqok) && SRinquiry(rp) == -1)
  344. Bprint(&bout, "warning: couldn't determine whether SCSI-1/SCSI-2 mode");
  345. return SRmodeselect6(rp, list, nbytes);
  346. }
  347. static long
  348. cmdmodeselect10(ScsiReq *rp, int argc, char *argv[])
  349. {
  350. uchar list[MaxDirData];
  351. long nbytes, ul;
  352. char *p;
  353. memset(list, 0, sizeof list);
  354. for(nbytes = 0; argc; argc--, argv++, nbytes++){
  355. if((ul = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
  356. rp->status = Status_BADARG;
  357. return -1;
  358. }
  359. list[nbytes] = ul;
  360. }
  361. if(!(rp->flags & Finqok) && SRinquiry(rp) == -1)
  362. Bprint(&bout, "warning: couldn't determine whether SCSI-1/SCSI-2 mode");
  363. return SRmodeselect10(rp, list, nbytes);
  364. }
  365. static long
  366. cmdmodesense6(ScsiReq *rp, int argc, char *argv[])
  367. {
  368. uchar list[MaxDirData], *lp, page;
  369. long i, n, nbytes, status;
  370. char *p;
  371. nbytes = sizeof list;
  372. switch(argc){
  373. default:
  374. rp->status = Status_BADARG;
  375. return -1;
  376. case 2:
  377. if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
  378. rp->status = Status_BADARG;
  379. return -1;
  380. }
  381. /*FALLTHROUGH*/
  382. case 1:
  383. if((page = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
  384. rp->status = Status_BADARG;
  385. return -1;
  386. }
  387. break;
  388. case 0:
  389. page = Allmodepages;
  390. break;
  391. }
  392. if((status = SRmodesense6(rp, page, list, nbytes)) == -1)
  393. return -1;
  394. lp = list;
  395. nbytes = list[0];
  396. Bprint(&bout, " Header\n ");
  397. for(i = 0; i < 4; i++){ /* header */
  398. Bprint(&bout, " %2.2uX", *lp);
  399. lp++;
  400. }
  401. Bputc(&bout, '\n');
  402. if(list[3]){ /* block descriptors */
  403. for(n = 0; n < list[3]/8; n++){
  404. Bprint(&bout, " Block %ld\n ", n);
  405. for(i = 0; i < 8; i++)
  406. Bprint(&bout, " %2.2uX", lp[i]);
  407. Bprint(&bout, " (density %2.2uX", lp[0]);
  408. Bprint(&bout, " blocks %d", (lp[1]<<16)|(lp[2]<<8)|lp[3]);
  409. Bprint(&bout, " length %d)", (lp[5]<<16)|(lp[6]<<8)|lp[7]);
  410. lp += 8;
  411. nbytes -= 8;
  412. Bputc(&bout, '\n');
  413. }
  414. }
  415. while(nbytes > 0){ /* pages */
  416. i = *(lp+1);
  417. nbytes -= i+2;
  418. Bprint(&bout, " Page %2.2uX %d\n ", *lp & 0x3F, *(lp+1));
  419. lp += 2;
  420. for(n = 0; n < i; n++){
  421. if(n && ((n & 0x0F) == 0))
  422. Bprint(&bout, "\n ");
  423. Bprint(&bout, " %2.2uX", *lp);
  424. lp++;
  425. }
  426. if(n && (n & 0x0F))
  427. Bputc(&bout, '\n');
  428. }
  429. return status;
  430. }
  431. static long
  432. cmdmodesense10(ScsiReq *rp, int argc, char *argv[])
  433. {
  434. uchar *list, *lp, page;
  435. long blen, i, n, nbytes, status;
  436. char *p;
  437. nbytes = MaxDirData;
  438. switch(argc){
  439. default:
  440. rp->status = Status_BADARG;
  441. return -1;
  442. case 2:
  443. if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
  444. rp->status = Status_BADARG;
  445. return -1;
  446. }
  447. /*FALLTHROUGH*/
  448. case 1:
  449. if((page = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
  450. rp->status = Status_BADARG;
  451. return -1;
  452. }
  453. break;
  454. case 0:
  455. page = Allmodepages;
  456. break;
  457. }
  458. list = malloc(nbytes);
  459. if(list == 0){
  460. rp->status = STnomem;
  461. return -1;
  462. }
  463. if((status = SRmodesense10(rp, page, list, nbytes)) == -1)
  464. return -1;
  465. lp = list;
  466. nbytes = ((list[0]<<8)|list[1]);
  467. Bprint(&bout, " Header\n ");
  468. for(i = 0; i < 8; i++){ /* header */
  469. Bprint(&bout, " %2.2uX", *lp);
  470. lp++;
  471. }
  472. Bputc(&bout, '\n');
  473. blen = (list[6]<<8)|list[7];
  474. if(blen){ /* block descriptors */
  475. for(n = 0; n < blen/8; n++){
  476. Bprint(&bout, " Block %ld\n ", n);
  477. for(i = 0; i < 8; i++)
  478. Bprint(&bout, " %2.2uX", lp[i]);
  479. Bprint(&bout, " (density %2.2uX", lp[0]);
  480. Bprint(&bout, " blocks %d", (lp[1]<<16)|(lp[2]<<8)|lp[3]);
  481. Bprint(&bout, " length %d)", (lp[5]<<16)|(lp[6]<<8)|lp[7]);
  482. lp += 8;
  483. nbytes -= 8;
  484. Bputc(&bout, '\n');
  485. }
  486. }
  487. /*
  488. * Special for ATA drives, page 0 is the drive info in 16-bit
  489. * chunks, little-endian, 256 in total. No decoding for now.
  490. */
  491. if(page == 0){
  492. for(n = 0; n < nbytes; n += 2){
  493. if(n && ((n & 0x1F) == 0))
  494. Bprint(&bout, "\n");
  495. Bprint(&bout, " %4.4uX", (*(lp+1)<<8)|*lp);
  496. lp += 2;
  497. }
  498. Bputc(&bout, '\n');
  499. }
  500. else
  501. while(nbytes > 0){ /* pages */
  502. i = *(lp+1);
  503. nbytes -= i+2;
  504. Bprint(&bout, " Page %2.2uX %d\n ", *lp & 0x3F, lp[1]);
  505. lp += 2;
  506. for(n = 0; n < i; n++){
  507. if(n && ((n & 0x0F) == 0))
  508. Bprint(&bout, "\n ");
  509. Bprint(&bout, " %2.2uX", *lp);
  510. lp++;
  511. }
  512. if(n && (n & 0x0F))
  513. Bputc(&bout, '\n');
  514. }
  515. free(list);
  516. return status;
  517. }
  518. static long
  519. start(ScsiReq *rp, int argc, char *argv[], uchar code)
  520. {
  521. char *p;
  522. if(argc && (code = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
  523. rp->status = Status_BADARG;
  524. return -1;
  525. }
  526. return SRstart(rp, code);
  527. }
  528. static long
  529. cmdstart(ScsiReq *rp, int argc, char *argv[])
  530. {
  531. return start(rp, argc, argv, 1);
  532. }
  533. static long
  534. cmdstop(ScsiReq *rp, int argc, char *argv[])
  535. {
  536. return start(rp, argc, argv, 0);
  537. }
  538. static long
  539. cmdeject(ScsiReq *rp, int argc, char *argv[])
  540. {
  541. return start(rp, argc, argv, 2);
  542. }
  543. static long
  544. cmdingest(ScsiReq *rp, int argc, char *argv[])
  545. {
  546. return start(rp, argc, argv, 3);
  547. }
  548. static long
  549. cmdcapacity(ScsiReq *rp, int argc, char *argv[])
  550. {
  551. uchar d[8];
  552. long n;
  553. USED(argc, argv);
  554. if((n = SRrcapacity(rp, d)) == -1)
  555. return -1;
  556. Bprint(&bout, " %ud %ud\n",
  557. d[0]<<24|d[1]<<16|d[2]<<8|d[3],
  558. d[4]<<24|d[5]<<16|d[6]<<8|d[7]);
  559. return n;
  560. }
  561. static long
  562. cmdblank(ScsiReq *rp, int argc, char *argv[])
  563. {
  564. uchar type, track;
  565. char *sp;
  566. type = track = 0;
  567. switch(argc){
  568. default:
  569. rp->status = Status_BADARG;
  570. return -1;
  571. case 2:
  572. if((type = strtoul(argv[1], &sp, 0)) == 0 && sp == argv[1]){
  573. rp->status = Status_BADARG;
  574. return -1;
  575. }
  576. if(type > 6){
  577. rp->status = Status_BADARG;
  578. return -1;
  579. }
  580. /*FALLTHROUGH*/
  581. case 1:
  582. if((track = strtoul(argv[0], &sp, 0)) == 0 && sp == argv[0]){
  583. rp->status = Status_BADARG;
  584. return -1;
  585. }
  586. /*FALLTHROUGH*/
  587. case 0:
  588. break;
  589. }
  590. return SRblank(rp, type, track);
  591. }
  592. static long
  593. cmdsynccache(ScsiReq *rp, int argc, char *argv[])
  594. {
  595. USED(argc, argv);
  596. return SRsynccache(rp);
  597. }
  598. static long
  599. cmdrtoc(ScsiReq *rp, int argc, char *argv[])
  600. {
  601. uchar d[100*8+4], format, track, *p;
  602. char *sp;
  603. long n, nbytes;
  604. int tdl;
  605. format = track = 0;
  606. switch(argc){
  607. default:
  608. rp->status = Status_BADARG;
  609. return -1;
  610. case 2:
  611. if((format = strtoul(argv[1], &sp, 0)) == 0 && sp == argv[1]){
  612. rp->status = Status_BADARG;
  613. return -1;
  614. }
  615. if(format > 4){
  616. rp->status = Status_BADARG;
  617. return -1;
  618. }
  619. /*FALLTHROUGH*/
  620. case 1:
  621. if((track = strtoul(argv[0], &sp, 0)) == 0 && sp == argv[0]){
  622. rp->status = Status_BADARG;
  623. return -1;
  624. }
  625. /*FALLTHROUGH*/
  626. case 0:
  627. break;
  628. }
  629. if((nbytes = SRTOC(rp, d, sizeof d, format, track)) == -1){
  630. if(rp->status == STok)
  631. Bprint(&bout, "\t(probably empty)\n");
  632. return -1;
  633. }
  634. tdl = (d[0]<<8)|d[1];
  635. switch(format){
  636. case 0:
  637. Bprint(&bout, "\ttoc/pma data length: 0x%uX\n", tdl);
  638. Bprint(&bout, "\tfirst track number: %d\n", d[2]);
  639. Bprint(&bout, "\tlast track number: %d\n", d[3]);
  640. for(p = &d[4], n = tdl-2; n; n -= 8, p += 8){
  641. Bprint(&bout, "\ttrack number: 0x%2.2uX\n", p[2]);
  642. Bprint(&bout, "\t\tcontrol: 0x%2.2uX\n", p[1] & 0x0F);
  643. Bprint(&bout, "\t\tblock address: 0x%uX\n",
  644. (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7]);
  645. }
  646. break;
  647. case 1:
  648. Bprint(&bout, "\tsessions data length: 0x%uX\n", tdl);
  649. Bprint(&bout, "\tnumber of finished sessions: %d\n", d[2]);
  650. Bprint(&bout, "\tunfinished session number: %d\n", d[3]);
  651. for(p = &d[4], n = tdl-2; n; n -= 8, p += 8){
  652. Bprint(&bout, "\tsession number: 0x%2.2uX\n", p[0]);
  653. Bprint(&bout, "\t\tfirst track number in session: 0x%2.2uX\n",
  654. p[2]);
  655. Bprint(&bout, "\t\tlogical start address: 0x%uX\n",
  656. (p[5]<<16)|(p[6]<<8)|p[7]);
  657. }
  658. break;
  659. case 2:
  660. Bprint(&bout, "\tfull TOC data length: 0x%uX\n", tdl);
  661. Bprint(&bout, "\tnumber of finished sessions: %d\n", d[2]);
  662. Bprint(&bout, "\tunfinished session number: %d\n", d[3]);
  663. for(p = &d[4], n = tdl-2; n > 0; n -= 11, p += 11){
  664. Bprint(&bout, "\tsession number: 0x%2.2uX\n", p[0]);
  665. Bprint(&bout, "\t\tcontrol: 0x%2.2uX\n", p[1] & 0x0F);
  666. Bprint(&bout, "\t\tADR: 0x%2.2uX\n", (p[1]>>4) & 0x0F);
  667. Bprint(&bout, "\t\tTNO: 0x%2.2uX\n", p[2]);
  668. Bprint(&bout, "\t\tPOINT: 0x%2.2uX\n", p[3]);
  669. Bprint(&bout, "\t\tMin: 0x%2.2uX\n", p[4]);
  670. Bprint(&bout, "\t\tSec: 0x%2.2uX\n", p[5]);
  671. Bprint(&bout, "\t\tFrame: 0x%2.2uX\n", p[6]);
  672. Bprint(&bout, "\t\tZero: 0x%2.2uX\n", p[7]);
  673. Bprint(&bout, "\t\tPMIN: 0x%2.2uX\n", p[8]);
  674. Bprint(&bout, "\t\tPSEC: 0x%2.2uX\n", p[9]);
  675. Bprint(&bout, "\t\tPFRAME: 0x%2.2uX\n", p[10]);
  676. }
  677. break;
  678. case 3:
  679. Bprint(&bout, "\tPMA data length: 0x%uX\n", tdl);
  680. for(p = &d[4], n = tdl-2; n > 0; n -= 11, p += 11){
  681. Bprint(&bout, "\t\tcontrol: 0x%2.2uX\n", p[1] & 0x0F);
  682. Bprint(&bout, "\t\tADR: 0x%2.2uX\n", (p[1]>>4) & 0x0F);
  683. Bprint(&bout, "\t\tTNO: 0x%2.2uX\n", p[2]);
  684. Bprint(&bout, "\t\tPOINT: 0x%2.2uX\n", p[3]);
  685. Bprint(&bout, "\t\tMin: 0x%2.2uX\n", p[4]);
  686. Bprint(&bout, "\t\tSec: 0x%2.2uX\n", p[5]);
  687. Bprint(&bout, "\t\tFrame: 0x%2.2uX\n", p[6]);
  688. Bprint(&bout, "\t\tZero: 0x%2.2uX\n", p[7]);
  689. Bprint(&bout, "\t\tPMIN: 0x%2.2uX\n", p[8]);
  690. Bprint(&bout, "\t\tPSEC: 0x%2.2uX\n", p[9]);
  691. Bprint(&bout, "\t\tPFRAME: 0x%2.2uX\n", p[10]);
  692. }
  693. break;
  694. case 4:
  695. Bprint(&bout, "\tATIP data length: 0x%uX\n", tdl);
  696. break;
  697. }
  698. for(n = 0; n < nbytes; n++){
  699. if(n && ((n & 0x0F) == 0))
  700. Bprint(&bout, "\n");
  701. Bprint(&bout, " %2.2uX", d[n]);
  702. }
  703. if(n && (n & 0x0F))
  704. Bputc(&bout, '\n');
  705. return nbytes;
  706. }
  707. static long
  708. cmdrdiscinfo(ScsiReq *rp, int argc, char*[])
  709. {
  710. uchar d[MaxDirData];
  711. int dl;
  712. long n, nbytes;
  713. switch(argc){
  714. default:
  715. rp->status = Status_BADARG;
  716. return -1;
  717. case 0:
  718. break;
  719. }
  720. if((nbytes = SRrdiscinfo(rp, d, sizeof d)) == -1)
  721. return -1;
  722. dl = (d[0]<<8)|d[1];
  723. Bprint(&bout, "\tdata length: 0x%uX\n", dl);
  724. Bprint(&bout, "\tinfo[2] 0x%2.2uX\n", d[2]);
  725. switch(d[2] & 0x03){
  726. case 0:
  727. Bprint(&bout, "\t\tEmpty\n");
  728. break;
  729. case 1:
  730. Bprint(&bout, "\t\tIncomplete disc (Appendable)\n");
  731. break;
  732. case 2:
  733. Bprint(&bout, "\t\tComplete (CD-ROM or last session is closed and has no next session pointer)\n");
  734. break;
  735. case 3:
  736. Bprint(&bout, "\t\tReserved\n");
  737. break;
  738. }
  739. switch((d[2]>>2) & 0x03){
  740. case 0:
  741. Bprint(&bout, "\t\tEmpty Session\n");
  742. break;
  743. case 1:
  744. Bprint(&bout, "\t\tIncomplete Session\n");
  745. break;
  746. case 2:
  747. Bprint(&bout, "\t\tReserved\n");
  748. break;
  749. case 3:
  750. Bprint(&bout, "\t\tComplete Session (only possible when disc Status is Complete)\n");
  751. break;
  752. }
  753. if(d[2] & 0x10)
  754. Bprint(&bout, "\t\tErasable\n");
  755. Bprint(&bout, "\tNumber of First Track on Disc %ud\n", d[3]);
  756. Bprint(&bout, "\tNumber of Sessions %ud\n", d[4]);
  757. Bprint(&bout, "\tFirst Track Number in Last Session %ud\n", d[5]);
  758. Bprint(&bout, "\tLast Track Number in Last Session %ud\n", d[6]);
  759. Bprint(&bout, "\tinfo[7] 0x%2.2uX\n", d[7]);
  760. if(d[7] & 0x20)
  761. Bprint(&bout, "\t\tUnrestricted Use Disc\n");
  762. if(d[7] & 0x40)
  763. Bprint(&bout, "\t\tDisc Bar Code Valid\n");
  764. if(d[7] & 0x80)
  765. Bprint(&bout, "\t\tDisc ID Valid\n");
  766. Bprint(&bout, "\tinfo[8] 0x%2.2uX\n", d[8]);
  767. switch(d[8]){
  768. case 0x00:
  769. Bprint(&bout, "\t\tCD-DA or CD-ROM Disc\n");
  770. break;
  771. case 0x10:
  772. Bprint(&bout, "\t\tCD-I Disc\n");
  773. break;
  774. case 0x20:
  775. Bprint(&bout, "\t\tCD-ROM XA Disc\n");
  776. break;
  777. case 0xFF:
  778. Bprint(&bout, "\t\tUndefined\n");
  779. break;
  780. default:
  781. Bprint(&bout, "\t\tReserved\n");
  782. break;
  783. }
  784. Bprint(&bout, "\tLast Session lead-in Start Time M/S/F: 0x%2.2uX/0x%2.2uX/0x%2.2uX\n",
  785. d[17], d[18], d[19]);
  786. Bprint(&bout, "\tLast Possible Start Time for Start of lead-out M/S/F: 0x%2.2uX/0x%2.2uX/0x%2.2uX\n",
  787. d[21], d[22], d[23]);
  788. for(n = 0; n < nbytes; n++){
  789. if(n && ((n & 0x0F) == 0))
  790. Bprint(&bout, "\n");
  791. Bprint(&bout, " %2.2uX", d[n]);
  792. }
  793. if(n && (n & 0x0F))
  794. Bputc(&bout, '\n');
  795. return nbytes;
  796. }
  797. static long
  798. cmdrtrackinfo(ScsiReq *rp, int argc, char *argv[])
  799. {
  800. uchar d[MaxDirData], track;
  801. char *sp;
  802. long n, nbytes;
  803. int dl;
  804. track = 0;
  805. switch(argc){
  806. default:
  807. rp->status = Status_BADARG;
  808. return -1;
  809. case 1:
  810. if((track = strtoul(argv[0], &sp, 0)) == 0 && sp == argv[0]){
  811. rp->status = Status_BADARG;
  812. return -1;
  813. }
  814. /*FALLTHROUGH*/
  815. case 0:
  816. break;
  817. }
  818. if((nbytes = SRrtrackinfo(rp, d, sizeof d, track)) == -1)
  819. return -1;
  820. dl = (d[0]<<8)|d[1];
  821. Bprint(&bout, "\tdata length: 0x%uX\n", dl);
  822. Bprint(&bout, "\Track Number %d\n", d[2]);
  823. Bprint(&bout, "\Session Number %d\n", d[3]);
  824. Bprint(&bout, "\tinfo[4] 0x%2.2uX\n", d[5]);
  825. Bprint(&bout, "\t\tTrack Mode 0x%2.2uX: ", d[5] & 0x0F);
  826. switch(d[5] & 0x0F){
  827. case 0x00:
  828. case 0x02:
  829. Bprint(&bout, "2 audio channels without pre-emphasis\n");
  830. break;
  831. case 0x01:
  832. case 0x03:
  833. Bprint(&bout, "2 audio channels with pre-emphasis of 50/15µs\n");
  834. break;
  835. case 0x08:
  836. case 0x0A:
  837. Bprint(&bout, "audio channels without pre-emphasis (reserved in CD-R/RW)\n");
  838. break;
  839. case 0x09:
  840. case 0x0B:
  841. Bprint(&bout, "audio channels with pre-emphasis of 50/15µs (reserved in CD-R/RW)\n");
  842. break;
  843. case 0x04:
  844. case 0x06:
  845. Bprint(&bout, "Data track, recorded uninterrupted\n");
  846. break;
  847. case 0x05:
  848. case 0x07:
  849. Bprint(&bout, "Data track, recorded incremental\n");
  850. break;
  851. default:
  852. Bprint(&bout, "(mode unknown)\n");
  853. break;
  854. }
  855. if(d[5] & 0x10)
  856. Bprint(&bout, "\t\tCopy\n");
  857. if(d[5] & 0x20)
  858. Bprint(&bout, "\t\tDamage\n");
  859. Bprint(&bout, "\tinfo[6] 0x%2.2uX\n", d[6]);
  860. Bprint(&bout, "\t\tData Mode 0x%2.2uX: ", d[6] & 0x0F);
  861. switch(d[6] & 0x0F){
  862. case 0x01:
  863. Bprint(&bout, "Mode 1 (ISO/IEC 10149)\n");
  864. break;
  865. case 0x02:
  866. Bprint(&bout, "Mode 2 (ISO/IEC 10149 or CD-ROM XA)\n");
  867. break;
  868. case 0x0F:
  869. Bprint(&bout, "Data Block Type unknown (no track descriptor block)\n");
  870. break;
  871. default:
  872. Bprint(&bout, "(Reserved)\n");
  873. break;
  874. }
  875. if(d[6] & 0x10)
  876. Bprint(&bout, "\t\tFP\n");
  877. if(d[6] & 0x20)
  878. Bprint(&bout, "\t\tPacket\n");
  879. if(d[6] & 0x40)
  880. Bprint(&bout, "\t\tBlank\n");
  881. if(d[6] & 0x80)
  882. Bprint(&bout, "\t\tRT\n");
  883. Bprint(&bout, "\tTrack Start Address 0x%8.8uX\n",
  884. (d[8]<<24)|(d[9]<<16)|(d[10]<<8)|d[11]);
  885. if(d[7] & 0x01)
  886. Bprint(&bout, "\tNext Writeable Address 0x%8.8uX\n",
  887. (d[12]<<24)|(d[13]<<16)|(d[14]<<8)|d[15]);
  888. Bprint(&bout, "\tFree Blocks 0x%8.8uX\n",
  889. (d[16]<<24)|(d[17]<<16)|(d[18]<<8)|d[19]);
  890. if((d[6] & 0x30) == 0x30)
  891. Bprint(&bout, "\tFixed Packet Size 0x%8.8uX\n",
  892. (d[20]<<24)|(d[21]<<16)|(d[22]<<8)|d[23]);
  893. Bprint(&bout, "\tTrack Size 0x%8.8uX\n",
  894. (d[24]<<24)|(d[25]<<16)|(d[26]<<8)|d[27]);
  895. for(n = 0; n < nbytes; n++){
  896. if(n && ((n & 0x0F) == 0))
  897. Bprint(&bout, "\n");
  898. Bprint(&bout, " %2.2uX", d[n]);
  899. }
  900. if(n && (n & 0x0F))
  901. Bputc(&bout, '\n');
  902. return nbytes;
  903. }
  904. static long
  905. cmdcdpause(ScsiReq *rp, int argc, char *argv[])
  906. {
  907. USED(argc, argv);
  908. return SRcdpause(rp, 0);
  909. }
  910. static long
  911. cmdcdresume(ScsiReq *rp, int argc, char *argv[])
  912. {
  913. USED(argc, argv);
  914. return SRcdpause(rp, 1);
  915. }
  916. static long
  917. cmdcdstop(ScsiReq *rp, int argc, char *argv[])
  918. {
  919. USED(argc, argv);
  920. return SRcdstop(rp);
  921. }
  922. static long
  923. cmdcdplay(ScsiReq *rp, int argc, char *argv[])
  924. {
  925. long length, start;
  926. char *sp;
  927. int raw;
  928. raw = 0;
  929. start = 0;
  930. if(argc && strcmp("-r", argv[0]) == 0){
  931. raw = 1;
  932. argc--, argv++;
  933. }
  934. length = 0xFFFFFFFF;
  935. switch(argc){
  936. default:
  937. rp->status = Status_BADARG;
  938. return -1;
  939. case 2:
  940. if(!raw || ((length = strtol(argv[1], &sp, 0)) == 0 && sp == argv[1])){
  941. rp->status = Status_BADARG;
  942. return -1;
  943. }
  944. /*FALLTHROUGH*/
  945. case 1:
  946. if((start = strtol(argv[0], &sp, 0)) == 0 && sp == argv[0]){
  947. rp->status = Status_BADARG;
  948. return -1;
  949. }
  950. /*FALLTHROUGH*/
  951. case 0:
  952. break;
  953. }
  954. return SRcdplay(rp, raw, start, length);
  955. }
  956. static long
  957. cmdcdload(ScsiReq *rp, int argc, char *argv[])
  958. {
  959. char *p;
  960. ulong slot;
  961. slot = 0;
  962. if(argc && (slot = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
  963. rp->status = Status_BADARG;
  964. return -1;
  965. }
  966. return SRcdload(rp, 1, slot);
  967. }
  968. static long
  969. cmdcdunload(ScsiReq *rp, int argc, char *argv[])
  970. {
  971. char *p;
  972. ulong slot;
  973. slot = 0;
  974. if(argc && (slot = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
  975. rp->status = Status_BADARG;
  976. return -1;
  977. }
  978. return SRcdload(rp, 0, slot);
  979. }
  980. static long
  981. cmdcdstatus(ScsiReq *rp, int argc, char *argv[])
  982. {
  983. uchar *list, *lp;
  984. long nbytes, status;
  985. int i, slots;
  986. USED(argc, argv);
  987. nbytes = 4096;
  988. list = malloc(nbytes);
  989. if(list == 0){
  990. rp->status = STnomem;
  991. return -1;
  992. }
  993. status = SRcdstatus(rp, list, nbytes);
  994. if(status == -1){
  995. free(list);
  996. return -1;
  997. }
  998. lp = list;
  999. Bprint(&bout, " Header\n ");
  1000. for(i = 0; i < 8; i++){ /* header */
  1001. Bprint(&bout, " %2.2uX", *lp);
  1002. lp++;
  1003. }
  1004. Bputc(&bout, '\n');
  1005. slots = ((list[6]<<8)|list[7])/4;
  1006. Bprint(&bout, " Slots\n ");
  1007. while(slots--){
  1008. Bprint(&bout, " %2.2uX %2.2uX %2.2uX %2.2uX\n ",
  1009. *lp, *(lp+1), *(lp+2), *(lp+3));
  1010. lp += 4;
  1011. }
  1012. free(list);
  1013. return status;
  1014. }
  1015. static long
  1016. cmdgetconf(ScsiReq *rp, int argc, char *argv[])
  1017. {
  1018. uchar *list;
  1019. long nbytes, status;
  1020. USED(argc, argv);
  1021. nbytes = 4096;
  1022. list = malloc(nbytes);
  1023. if(list == 0){
  1024. rp->status = STnomem;
  1025. return -1;
  1026. }
  1027. status = SRgetconf(rp, list, nbytes);
  1028. if(status == -1){
  1029. free(list);
  1030. return -1;
  1031. }
  1032. /* to be done... */
  1033. free(list);
  1034. return status;
  1035. }
  1036. static long
  1037. cmdfwaddr(ScsiReq *rp, int argc, char *argv[])
  1038. {
  1039. uchar d[MaxDirData], npa, track, mode;
  1040. long n;
  1041. char *p;
  1042. npa = mode = track = 0;
  1043. switch(argc){
  1044. default:
  1045. rp->status = Status_BADARG;
  1046. return -1;
  1047. case 3:
  1048. if((npa = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
  1049. rp->status = Status_BADARG;
  1050. return -1;
  1051. }
  1052. /*FALLTHROUGH*/
  1053. case 2:
  1054. if((mode = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
  1055. rp->status = Status_BADARG;
  1056. return -1;
  1057. }
  1058. /*FALLTHROUGH*/
  1059. case 1:
  1060. if((track = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
  1061. rp->status = Status_BADARG;
  1062. return -1;
  1063. }
  1064. break;
  1065. case 0:
  1066. break;
  1067. }
  1068. if((n = SRfwaddr(rp, track, mode, npa, d)) == -1)
  1069. return -1;
  1070. Bprint(&bout, "%ud %ud\n", d[0], (d[1]<<24)|(d[2]<<16)|(d[3]<<8)|d[4]);
  1071. return n;
  1072. }
  1073. static long
  1074. cmdtreserve(ScsiReq *rp, int argc, char *argv[])
  1075. {
  1076. long nbytes;
  1077. char *p;
  1078. if(argc != 1 || ((nbytes = strtoul(argv[0], &p, 0)) == 0 && p == argv[0])){
  1079. rp->status = Status_BADARG;
  1080. return -1;
  1081. }
  1082. return SRtreserve(rp, nbytes);
  1083. }
  1084. static long
  1085. cmdtrackinfo(ScsiReq *rp, int argc, char *argv[])
  1086. {
  1087. uchar d[MaxDirData], track;
  1088. long n;
  1089. ulong ul;
  1090. char *p;
  1091. track = 0;
  1092. if(argc && (track = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
  1093. rp->status = Status_BADARG;
  1094. return -1;
  1095. }
  1096. if((n = SRtinfo(rp, track, d)) == -1)
  1097. return -1;
  1098. Bprint(&bout, "buffer length: 0x%uX\n", d[0]);
  1099. Bprint(&bout, "number of tracks: 0x%uX\n", d[1]);
  1100. ul = (d[2]<<24)|(d[3]<<16)|(d[4]<<8)|d[5];
  1101. Bprint(&bout, "start address: 0x%luX\n", ul);
  1102. ul = (d[6]<<24)|(d[7]<<16)|(d[8]<<8)|d[9];
  1103. Bprint(&bout, "track length: 0x%luX\n", ul);
  1104. Bprint(&bout, "track mode: 0x%uX\n", d[0x0A] & 0x0F);
  1105. Bprint(&bout, "track status: 0x%uX\n", (d[0x0A]>>4) & 0x0F);
  1106. Bprint(&bout, "data mode: 0x%uX\n", d[0x0B] & 0x0F);
  1107. ul = (d[0x0C]<<24)|(d[0x0D]<<16)|(d[0x0E]<<8)|d[0x0F];
  1108. Bprint(&bout, "free blocks: 0x%luX\n", ul);
  1109. return n;
  1110. }
  1111. static long
  1112. cmdwtrack(ScsiReq *rp, int argc, char *argv[])
  1113. {
  1114. uchar mode, track;
  1115. long n, nbytes, total, x;
  1116. int fd, pid;
  1117. char *p;
  1118. mode = track = 0;
  1119. nbytes = 0;
  1120. switch(argc){
  1121. default:
  1122. rp->status = Status_BADARG;
  1123. return -1;
  1124. case 4:
  1125. if((mode = strtoul(argv[3], &p, 0)) == 0 && p == argv[3]){
  1126. rp->status = Status_BADARG;
  1127. return -1;
  1128. }
  1129. /*FALLTHROUGH*/
  1130. case 3:
  1131. if((track = strtoul(argv[2], &p, 0)) == 0 && p == argv[2]){
  1132. rp->status = Status_BADARG;
  1133. return -1;
  1134. }
  1135. /*FALLTHROUGH*/
  1136. case 2:
  1137. if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
  1138. rp->status = Status_BADARG;
  1139. return -1;
  1140. }
  1141. /*FALLTHROUGH*/
  1142. case 1:
  1143. if((fd = mkfile(argv[0], OREAD, &pid)) == -1){
  1144. rp->status = Status_BADARG;
  1145. return -1;
  1146. }
  1147. break;
  1148. }
  1149. total = 0;
  1150. n = MIN(nbytes, maxiosize);
  1151. if((n = readn(fd, rwbuf, n)) == -1){
  1152. fprint(2, "file read failed %r\n");
  1153. close(fd);
  1154. return -1;
  1155. }
  1156. if((x = SRwtrack(rp, rwbuf, n, track, mode)) != n){
  1157. fprint(2, "wtrack: write incomplete: asked %ld, did %ld\n", n, x);
  1158. if(rp->status == STok)
  1159. rp->status = Status_SW;
  1160. close(fd);
  1161. return -1;
  1162. }
  1163. nbytes -= n;
  1164. total += n;
  1165. while(nbytes){
  1166. n = MIN(nbytes, maxiosize);
  1167. if((n = read(fd, rwbuf, n)) == -1){
  1168. break;
  1169. }
  1170. if((x = SRwrite(rp, rwbuf, n)) != n){
  1171. fprint(2, "write: write incomplete: asked %ld, did %ld\n", n, x);
  1172. if(rp->status == STok)
  1173. rp->status = Status_SW;
  1174. break;
  1175. }
  1176. nbytes -= n;
  1177. total += n;
  1178. }
  1179. close(fd);
  1180. if(pid >= 0 && waitfor(pid)){
  1181. rp->status = Status_SW;
  1182. return -1;
  1183. }
  1184. return total;
  1185. }
  1186. static long
  1187. cmdload(ScsiReq *rp, int argc, char *argv[])
  1188. {
  1189. USED(argc, argv);
  1190. return SRmload(rp, 0);
  1191. }
  1192. static long
  1193. cmdunload(ScsiReq *rp, int argc, char *argv[])
  1194. {
  1195. USED(argc, argv);
  1196. return SRmload(rp, 1);
  1197. }
  1198. static long
  1199. cmdfixation(ScsiReq *rp, int argc, char *argv[])
  1200. {
  1201. uchar type;
  1202. char *p;
  1203. type = 0;
  1204. if(argc && (type = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
  1205. rp->status = Status_BADARG;
  1206. return -1;
  1207. }
  1208. return SRfixation(rp, type);
  1209. }
  1210. static long
  1211. cmdeinit(ScsiReq *rp, int argc, char *argv[])
  1212. {
  1213. USED(argc, argv);
  1214. return SReinitialise(rp);
  1215. }
  1216. static long
  1217. cmdmmove(ScsiReq *rp, int argc, char *argv[])
  1218. {
  1219. int transport, source, destination, invert;
  1220. char *p;
  1221. invert = 0;
  1222. switch(argc){
  1223. default:
  1224. rp->status = Status_BADARG;
  1225. return -1;
  1226. case 4:
  1227. if((invert = strtoul(argv[3], &p, 0)) == 0 && p == argv[3]){
  1228. rp->status = Status_BADARG;
  1229. return -1;
  1230. }
  1231. /*FALLTHROUGH*/
  1232. case 3:
  1233. if((transport = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
  1234. rp->status = Status_BADARG;
  1235. return -1;
  1236. }
  1237. if((source = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
  1238. rp->status = Status_BADARG;
  1239. return -1;
  1240. }
  1241. if((destination = strtoul(argv[2], &p, 0)) == 0 && p == argv[2]){
  1242. rp->status = Status_BADARG;
  1243. return -1;
  1244. }
  1245. break;
  1246. }
  1247. return SRmmove(rp, transport, source, destination, invert);
  1248. }
  1249. static long
  1250. cmdestatus(ScsiReq *rp, int argc, char *argv[])
  1251. {
  1252. uchar *list, *lp, type;
  1253. long d, i, n, nbytes, status;
  1254. char *p;
  1255. type = 0;
  1256. nbytes = 4096;
  1257. switch(argc){
  1258. default:
  1259. rp->status = Status_BADARG;
  1260. return -1;
  1261. case 2:
  1262. if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
  1263. rp->status = Status_BADARG;
  1264. return -1;
  1265. }
  1266. /*FALLTHROUGH*/
  1267. case 1:
  1268. if((type = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
  1269. rp->status = Status_BADARG;
  1270. return -1;
  1271. }
  1272. break;
  1273. case 0:
  1274. break;
  1275. }
  1276. list = malloc(nbytes);
  1277. if(list == 0){
  1278. rp->status = STnomem;
  1279. return -1;
  1280. }
  1281. status = SRestatus(rp, type, list, nbytes);
  1282. if(status == -1){
  1283. free(list);
  1284. return -1;
  1285. }
  1286. lp = list;
  1287. nbytes = ((lp[5]<<16)|(lp[6]<<8)|lp[7])-8;
  1288. Bprint(&bout, " Header\n ");
  1289. for(i = 0; i < 8; i++){ /* header */
  1290. Bprint(&bout, " %2.2uX", *lp);
  1291. lp++;
  1292. }
  1293. Bputc(&bout, '\n');
  1294. while(nbytes > 0){ /* pages */
  1295. i = ((lp[5]<<16)|(lp[6]<<8)|lp[7]);
  1296. nbytes -= i+8;
  1297. Bprint(&bout, " Type");
  1298. for(n = 0; n < 8; n++) /* header */
  1299. Bprint(&bout, " %2.2uX", lp[n]);
  1300. Bprint(&bout, "\n ");
  1301. d = (lp[2]<<8)|lp[3];
  1302. lp += 8;
  1303. for(n = 0; n < i; n++){
  1304. if(n && (n % d) == 0)
  1305. Bprint(&bout, "\n ");
  1306. Bprint(&bout, " %2.2uX", *lp);
  1307. lp++;
  1308. }
  1309. if(n && (n % d))
  1310. Bputc(&bout, '\n');
  1311. }
  1312. free(list);
  1313. return status;
  1314. }
  1315. static long
  1316. cmdhelp(ScsiReq *rp, int argc, char *argv[])
  1317. {
  1318. ScsiCmd *cp;
  1319. char *p;
  1320. USED(rp);
  1321. if(argc)
  1322. p = argv[0];
  1323. else
  1324. p = 0;
  1325. for(cp = scsicmd; cp->name; cp++){
  1326. if(p == 0 || strcmp(p, cp->name) == 0)
  1327. Bprint(&bout, "%s\n", cp->help);
  1328. }
  1329. return 0;
  1330. }
  1331. static long
  1332. cmdprobe(ScsiReq *rp, int argc, char *argv[])
  1333. {
  1334. char buf[32];
  1335. ScsiReq scsireq;
  1336. char *ctlr, *unit;
  1337. USED(argc, argv);
  1338. rp->status = STok;
  1339. scsireq.flags = 0;
  1340. for(ctlr="CDEFGHIJ0123456789abcdef"; *ctlr; ctlr++) {
  1341. /*
  1342. * I can guess how many units you have.
  1343. * SATA controllers can have more than two drives each.
  1344. */
  1345. if(*ctlr >= 'C' && *ctlr <= 'D')
  1346. unit = "01";
  1347. else if((*ctlr >= '0' && *ctlr <= '9')
  1348. || (*ctlr >= 'a' && *ctlr <= 'f'))
  1349. unit = "0123456789abcdef"; /* allow wide scsi */
  1350. else
  1351. unit = "01234567";
  1352. for(; *unit; unit++){
  1353. sprint(buf, "/dev/sd%c%c", *ctlr, *unit);
  1354. if(SRopenraw(&scsireq, buf) == -1)
  1355. continue;
  1356. SRreqsense(&scsireq);
  1357. switch(scsireq.status){
  1358. case STok:
  1359. case Status_SD:
  1360. Bprint(&bout, "%s: ", buf);
  1361. cmdinquiry(&scsireq, 0, 0);
  1362. break;
  1363. }
  1364. SRclose(&scsireq);
  1365. }
  1366. }
  1367. return 0;
  1368. }
  1369. static long
  1370. cmdclose(ScsiReq *rp, int argc, char *argv[])
  1371. {
  1372. USED(argc, argv);
  1373. return SRclose(rp);
  1374. }
  1375. static long
  1376. cmdopen(ScsiReq *rp, int argc, char *argv[])
  1377. {
  1378. int raw;
  1379. long status;
  1380. raw = 0;
  1381. if(argc && strcmp("-r", argv[0]) == 0){
  1382. raw = 1;
  1383. argc--, argv++;
  1384. }
  1385. if(argc != 1){
  1386. rp->status = Status_BADARG;
  1387. return -1;
  1388. }
  1389. if(raw == 0){
  1390. if((status = SRopen(rp, argv[0])) != -1 && verbose)
  1391. Bprint(&bout, "%sblock size: %ld\n",
  1392. rp->flags&Fbfixed? "fixed ": "", rp->lbsize);
  1393. }
  1394. else {
  1395. status = SRopenraw(rp, argv[0]);
  1396. rp->lbsize = 512;
  1397. }
  1398. return status;
  1399. }
  1400. static ScsiCmd scsicmd[] = {
  1401. { "ready", cmdready, 1, /*[0x00]*/
  1402. "ready",
  1403. },
  1404. { "rewind", cmdrewind, 1, /*[0x01]*/
  1405. "rewind",
  1406. },
  1407. { "rezero", cmdrewind, 1, /*[0x01]*/
  1408. "rezero",
  1409. },
  1410. { "reqsense", cmdreqsense, 1, /*[0x03]*/
  1411. "reqsense",
  1412. },
  1413. { "format", cmdformat, 0, /*[0x04]*/
  1414. "format",
  1415. },
  1416. { "rblimits", cmdrblimits, 1, /*[0x05]*/
  1417. "rblimits",
  1418. },
  1419. { "read", cmdread, 1, /*[0x08]*/
  1420. "read [|]file [nbytes]",
  1421. },
  1422. { "write", cmdwrite, 1, /*[0x0A]*/
  1423. "write [|]file [nbytes]",
  1424. },
  1425. { "seek", cmdseek, 1, /*[0x0B]*/
  1426. "seek offset [whence]",
  1427. },
  1428. { "filemark", cmdfilemark, 1, /*[0x10]*/
  1429. "filemark [howmany]",
  1430. },
  1431. { "space", cmdspace, 1, /*[0x11]*/
  1432. "space [-f] [-b] [[--] howmany]",
  1433. },
  1434. { "inquiry", cmdinquiry, 1, /*[0x12]*/
  1435. "inquiry",
  1436. },
  1437. { "modeselect6",cmdmodeselect6, 1, /*[0x15] */
  1438. "modeselect6 bytes...",
  1439. },
  1440. { "modeselect", cmdmodeselect10, 1, /*[0x55] */
  1441. "modeselect bytes...",
  1442. },
  1443. { "modesense6", cmdmodesense6, 1, /*[0x1A]*/
  1444. "modesense6 [page [nbytes]]",
  1445. },
  1446. { "modesense", cmdmodesense10, 1, /*[0x5A]*/
  1447. "modesense [page [nbytes]]",
  1448. },
  1449. { "start", cmdstart, 1, /*[0x1B]*/
  1450. "start [code]",
  1451. },
  1452. { "stop", cmdstop, 1, /*[0x1B]*/
  1453. "stop",
  1454. },
  1455. { "eject", cmdeject, 1, /*[0x1B]*/
  1456. "eject",
  1457. },
  1458. { "ingest", cmdingest, 1, /*[0x1B]*/
  1459. "ingest",
  1460. },
  1461. { "capacity", cmdcapacity, 1, /*[0x25]*/
  1462. "capacity",
  1463. },
  1464. { "blank", cmdblank, 1, /*[0xA1]*/
  1465. "blank [track/LBA [type]]",
  1466. },
  1467. // { "synccache", cmdsynccache, 1, /*[0x35]*/
  1468. // "synccache",
  1469. // },
  1470. { "rtoc", cmdrtoc, 1, /*[0x43]*/
  1471. "rtoc [track/session-number [format]]",
  1472. },
  1473. { "rdiscinfo", cmdrdiscinfo, 1, /*[0x51]*/
  1474. "rdiscinfo",
  1475. },
  1476. { "rtrackinfo", cmdrtrackinfo, 1, /*[0x52]*/
  1477. "rtrackinfo [track]",
  1478. },
  1479. { "cdpause", cmdcdpause, 1, /*[0x4B]*/
  1480. "cdpause",
  1481. },
  1482. { "cdresume", cmdcdresume, 1, /*[0x4B]*/
  1483. "cdresume",
  1484. },
  1485. { "cdstop", cmdcdstop, 1, /*[0x4E]*/
  1486. "cdstop",
  1487. },
  1488. { "cdplay", cmdcdplay, 1, /*[0xA5]*/
  1489. "cdplay [track-number] or [-r [LBA [length]]]",
  1490. },
  1491. { "cdload", cmdcdload, 1, /*[0xA6*/
  1492. "cdload [slot]",
  1493. },
  1494. { "cdunload", cmdcdunload, 1, /*[0xA6]*/
  1495. "cdunload [slot]",
  1496. },
  1497. { "cdstatus", cmdcdstatus, 1, /*[0xBD]*/
  1498. "cdstatus",
  1499. },
  1500. // { "getconf", cmdgetconf, 1, /*[0x46]*/
  1501. // "getconf",
  1502. // },
  1503. // { "fwaddr", cmdfwaddr, 1, /*[0xE2]*/
  1504. // "fwaddr [track [mode [npa]]]",
  1505. // },
  1506. // { "treserve", cmdtreserve, 1, /*[0xE4]*/
  1507. // "treserve nbytes",
  1508. // },
  1509. // { "trackinfo", cmdtrackinfo, 1, /*[0xE5]*/
  1510. // "trackinfo [track]",
  1511. // },
  1512. // { "wtrack", cmdwtrack, 1, /*[0xE6]*/
  1513. // "wtrack [|]file [nbytes [track [mode]]]",
  1514. // },
  1515. // { "load", cmdload, 1, /*[0xE7]*/
  1516. // "load",
  1517. // },
  1518. // { "unload", cmdunload, 1, /*[0xE7]*/
  1519. // "unload",
  1520. // },
  1521. // { "fixation", cmdfixation, 1, /*[0xE9]*/
  1522. // "fixation [toc-type]",
  1523. // },
  1524. { "einit", cmdeinit, 1, /*[0x07]*/
  1525. "einit",
  1526. },
  1527. { "estatus", cmdestatus, 1, /*[0xB8]*/
  1528. "estatus",
  1529. },
  1530. { "mmove", cmdmmove, 1, /*[0xA5]*/
  1531. "mmove transport source destination [invert]",
  1532. },
  1533. { "help", cmdhelp, 0,
  1534. "help",
  1535. },
  1536. { "probe", cmdprobe, 0,
  1537. "probe",
  1538. },
  1539. { "close", cmdclose, 1,
  1540. "close",
  1541. },
  1542. { "open", cmdopen, 0,
  1543. "open [-r] sddev",
  1544. },
  1545. { 0, 0 },
  1546. };
  1547. #define SEP(c) (((c)==' ')||((c)=='\t')||((c)=='\n'))
  1548. static char *
  1549. tokenise(char *s, char **start, char **end)
  1550. {
  1551. char *to;
  1552. Rune r;
  1553. int n;
  1554. while(*s && SEP(*s)) /* skip leading white space */
  1555. s++;
  1556. to = *start = s;
  1557. while(*s){
  1558. n = chartorune(&r, s);
  1559. if(SEP(r)){
  1560. if(to != *start) /* we have data */
  1561. break;
  1562. s += n; /* null string - keep looking */
  1563. while(*s && SEP(*s))
  1564. s++;
  1565. to = *start = s;
  1566. }
  1567. else if(r == '\''){
  1568. s += n; /* skip leading quote */
  1569. while(*s){
  1570. n = chartorune(&r, s);
  1571. if(r == '\''){
  1572. if(s[1] != '\'')
  1573. break;
  1574. s++; /* embedded quote */
  1575. }
  1576. while (n--)
  1577. *to++ = *s++;
  1578. }
  1579. if(!*s) /* no trailing quote */
  1580. break;
  1581. s++; /* skip trailing quote */
  1582. }
  1583. else {
  1584. while(n--)
  1585. *to++ = *s++;
  1586. }
  1587. }
  1588. *end = to;
  1589. return s;
  1590. }
  1591. static int
  1592. parse(char *s, char *fields[], int nfields)
  1593. {
  1594. int c, argc;
  1595. char *start, *end;
  1596. argc = 0;
  1597. c = *s;
  1598. while(c){
  1599. s = tokenise(s, &start, &end);
  1600. c = *s++;
  1601. if(*start == 0)
  1602. break;
  1603. if(argc >= nfields-1)
  1604. return -1;
  1605. *end = 0;
  1606. fields[argc++] = start;
  1607. }
  1608. fields[argc] = 0;
  1609. return argc;
  1610. }
  1611. static void
  1612. usage(void)
  1613. {
  1614. fprint(2, "usage: %s [-6eq] [-m maxiosize] [[-r] /dev/sdXX]\n", argv0);
  1615. exits("usage");
  1616. }
  1617. static struct {
  1618. int status;
  1619. char* description;
  1620. } description[] = {
  1621. STnomem, "buffer allocation failed",
  1622. STtimeout, "bus timeout",
  1623. STharderr, "controller error of some kind",
  1624. STok, "good",
  1625. STcheck, "check condition",
  1626. STcondmet, "condition met/good",
  1627. STbusy, "busy ",
  1628. STintok, "intermediate/good",
  1629. STintcondmet, "intermediate/condition met/good",
  1630. STresconf, "reservation conflict",
  1631. STterminated, "command terminated",
  1632. STqfull, "queue full",
  1633. Status_SD, "sense-data available",
  1634. Status_SW, "internal software error",
  1635. Status_BADARG, "bad argument to request",
  1636. 0, 0,
  1637. };
  1638. void
  1639. main(int argc, char *argv[])
  1640. {
  1641. ScsiReq target;
  1642. char *ap, *av[256];
  1643. int ac, i, raw = 0;
  1644. ScsiCmd *cp;
  1645. long status;
  1646. ARGBEGIN {
  1647. case 'e':
  1648. exabyte = 1;
  1649. /* fallthrough */
  1650. case '6':
  1651. force6bytecmds = 1;
  1652. break;
  1653. case 'm':
  1654. ap = ARGF();
  1655. if(ap == nil)
  1656. usage();
  1657. maxiosize = atol(ap);
  1658. if(maxiosize < 512 || maxiosize > MaxIOsize)
  1659. sysfatal("max-xfer < 512 or > %d", MaxIOsize);
  1660. break;
  1661. case 'r': /* must be last option and not bundled */
  1662. raw++;
  1663. break;
  1664. case 'q':
  1665. verbose = 0;
  1666. break;
  1667. default:
  1668. usage();
  1669. } ARGEND
  1670. if(Binit(&bin, 0, OREAD) == Beof || Binit(&bout, 1, OWRITE) == Beof){
  1671. fprint(2, "%s: can't init bio: %r\n", argv0);
  1672. exits("Binit");
  1673. }
  1674. memset(&target, 0, sizeof target);
  1675. if (raw) { /* hack for -r */
  1676. ++argc;
  1677. --argv;
  1678. }
  1679. if(argc && cmdopen(&target, argc, argv) == -1) {
  1680. fprint(2, "open failed\n");
  1681. usage();
  1682. }
  1683. Bflush(&bout);
  1684. while(ap = Brdline(&bin, '\n')){
  1685. ap[Blinelen(&bin)-1] = 0;
  1686. switch(ac = parse(ap, av, nelem(av))){
  1687. default:
  1688. for(cp = scsicmd; cp->name; cp++){
  1689. if(strcmp(cp->name, av[0]) == 0)
  1690. break;
  1691. }
  1692. if(cp->name == 0){
  1693. Bprint(&bout, "eh?\n");
  1694. break;
  1695. }
  1696. if((target.flags & Fopen) == 0 && cp->open){
  1697. Bprint(&bout, "no current target\n");
  1698. break;
  1699. }
  1700. if((status = (*cp->f)(&target, ac-1, &av[1])) != -1){
  1701. if(verbose)
  1702. Bprint(&bout, "ok %ld\n", status);
  1703. break;
  1704. }
  1705. for(i = 0; description[i].description; i++){
  1706. if(target.status != description[i].status)
  1707. continue;
  1708. if(target.status == Status_SD)
  1709. makesense(&target);
  1710. else
  1711. Bprint(&bout, "%s\n", description[i].description);
  1712. break;
  1713. }
  1714. break;
  1715. case -1:
  1716. Bprint(&bout, "eh?\n");
  1717. break;
  1718. case 0:
  1719. break;
  1720. }
  1721. Bflush(&bout);
  1722. }
  1723. exits(0);
  1724. }