scuzz.c 34 KB

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