scuzz.c 37 KB

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