home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1993 #2 / Image.iso / os2 / gtak212b.zip / SOURCE.ZIP / TAPE / tape.c < prev    next >
C/C++ Source or Header  |  1992-09-12  |  13KB  |  639 lines

  1. /*****************************************************************************
  2.  * $Id: tape.c,v 1.3 1992/09/12 18:10:55 ak Exp $
  3.  *****************************************************************************
  4.  * $Log: tape.c,v $
  5.  * Revision 1.3  1992/09/12  18:10:55  ak
  6.  * Added scsi_name
  7.  * Added device name support to tctl.c
  8.  *
  9.  * Revision 1.2  1992/09/02  19:05:22  ak
  10.  * Version 2.0
  11.  * - EMX version
  12.  * - AIX version
  13.  * - SCSI-2 commands
  14.  * - ADD Driver
  15.  * - blocksize support
  16.  *
  17.  * Revision 1.1.1.1  1992/01/06  20:27:39  ak
  18.  * Interface now based on ST01 and ASPI.
  19.  * AHA_DRVR no longer supported.
  20.  * Files reorganized.
  21.  *
  22.  * Revision 1.1  1992/01/06  20:27:37  ak
  23.  * Initial revision
  24.  *
  25.  *****************************************************************************/
  26.  
  27. static char *rcsid = "$Id: tape.c,v 1.3 1992/09/12 18:10:55 ak Exp $";
  28.  
  29.  
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <limits.h>
  33.  
  34. #ifdef __EMX__
  35. #ifndef _far
  36. #define _far
  37. #endif
  38. #endif
  39.  
  40. #include "scsi.h"
  41. #include "tape.h"
  42. #include "scsitape.h"
  43.  
  44. #define SenseLength    16
  45. #define SenseAlloc    16
  46.  
  47. static int        target = 4;
  48. static unsigned char    cdb [10];
  49. static unsigned char    sense_buf [SenseAlloc];
  50. static unsigned char *    sense_ptr = sense_buf;
  51. static int        sense_len = SenseLength;
  52. static int        active;
  53. static long        active_nb;
  54. static void *        ctrl;
  55. int            scsiLevel = 1;
  56. static long        blocksize = 512;
  57. static long        valid_blocksize = 0;
  58.  
  59. #define int16(x)    ((unsigned)(x)[0] << 8 | (x)[1])
  60. #define int24(x)    ((unsigned long)int16(x) << 8 | (x)[2])
  61. #define int32(x)    ((unsigned long)int24(x) << 8 | (x)[3])
  62.  
  63. int
  64. tape_cmd(void *cdb, int cdb_len)
  65. {
  66.     return scsi_cmd(target, 0, cdb, cdb_len, sense_ptr, sense_len, (void *)0, 0L, 0);
  67. }
  68.  
  69. int
  70. tape_read_cmd(void *cdb, int cdb_len, void _far *data, long length)
  71. {
  72.     return scsi_cmd(target, 0, cdb, cdb_len, sense_ptr, sense_len, data, length, 1);
  73. }
  74.  
  75. int
  76. tape_write_cmd(void *cdb, int cdb_len, void _far *data, long length)
  77. {
  78.     return scsi_cmd(target, 0, cdb, cdb_len, sense_ptr, sense_len, data, length, 0);
  79. }
  80.  
  81. static void
  82. init()
  83. {
  84.     char *env;
  85.     long size;
  86.  
  87.     sense_ptr = sense_buf;
  88.     sense_len = SenseLength;
  89.     if ((env = getenv("TAPEMODE")) != NULL)
  90.         scsiLevel = atoi(env);
  91.     else
  92.         scsiLevel = senseMode;
  93. }
  94.  
  95. void
  96. tape_init(void)
  97. {
  98.     scsi_init();
  99.     init();
  100. }
  101.  
  102. void
  103. tape_name(char *name)
  104. {
  105.     scsi_name(name);
  106.     init();
  107. }
  108.  
  109. void
  110. tape_file(int fd)
  111. {
  112.     scsi_file(fd);
  113.     init();
  114. }
  115.  
  116. void
  117. tape_term(void)
  118. {
  119.     scsi_term();
  120. }
  121.  
  122. int
  123. tape_reset(int bus)
  124. {
  125.     return scsi_reset(target, 0, bus);
  126. }
  127.  
  128. void
  129. tape_trace(int level)
  130. {
  131.     scsi_trace(level);
  132. }
  133.  
  134. int
  135. tape_target(int no)
  136. {
  137.     int old = target;
  138.     target = no;
  139.     return old;
  140. }
  141.  
  142. void
  143. tape_sense(void *data, int len)
  144. {
  145.     if (len >= 8 && data) {
  146.         sense_ptr = data;
  147.         sense_len = len;
  148.     } else {
  149.         sense_ptr = sense_buf;
  150.         sense_len = SenseLength;
  151.     }
  152. }
  153.  
  154. char *
  155. tape_error(int code)
  156. {
  157.     switch (code) {
  158.     case EndOfData: return "End of data";
  159.     case EndOfTape: return "End of tape";
  160.     case FileMark:  return "File mark";
  161.     }
  162.     return scsi_error(code);
  163. }
  164.  
  165. int
  166. tape_inquiry(void *data, int len)
  167. {
  168.     cdb[0] = CmdInquiry;
  169.     cdb[1] = 0;
  170.     cdb[2] = 0;
  171.     cdb[3] = 0;
  172.     cdb[4] = len;
  173.     cdb[5] = 0;
  174.     return tape_read_cmd(cdb, 6, data, len);
  175. }    
  176.  
  177. int
  178. tape_mode_sense(int page, void *data, int len)
  179. {
  180.     cdb[0] = CmdModeSense;
  181.     cdb[1] = 0;
  182.     cdb[2] = page;
  183.     cdb[3] = 0;
  184.     cdb[4] = len;
  185.     cdb[5] = 0;
  186.     return tape_read_cmd(cdb, 6, data, len);
  187. }    
  188.  
  189. int
  190. tape_mode_select(int page, void *data, int len, int SMP)
  191. {
  192.     cdb[0] = CmdModeSelect;
  193.     cdb[1] = 0;
  194.     cdb[2] = page;
  195.     cdb[3] = 0;
  196.     cdb[4] = len;
  197.     cdb[5] = SMP ? 0x40 : 0x00;
  198.     return tape_write_cmd(cdb, 6, data, len);
  199. }    
  200.  
  201. int
  202. tape_rewind(int imed)
  203. {
  204.     cdb[0] = SeqRewind;
  205.     cdb[1] = imed ? 1 : 0;
  206.     cdb[2] = 0;
  207.     cdb[3] = 0;
  208.     cdb[4] = 0;
  209.     cdb[5] = 0;
  210.     return tape_cmd(cdb, 6);
  211. }
  212.  
  213. long
  214. tape_tell(void)
  215. {
  216.     int rc;
  217.  
  218.     if (scsiLevel >= 2) {
  219.         unsigned char addr [20];
  220.         cdb[0] = SeqReadPosition;
  221.         cdb[1] = 1;
  222.         cdb[2] = 0;
  223.         cdb[3] = 0;
  224.         cdb[4] = 0;
  225.         cdb[5] = 0;
  226.         cdb[6] = 0;
  227.         cdb[7] = 0;
  228.         cdb[8] = 0;
  229.         cdb[9] = 0;
  230.         if ((rc = tape_read_cmd(cdb, 10, addr, 20)) != 0)
  231.             return rc;
  232.         return (long)addr[4] << 24 | (long)addr[5] << 16
  233.              | (long)addr[6] << 8 | addr[7];
  234.     } else {
  235.         unsigned char addr [3];
  236.         cdb[0] = SeqRequestBlockAddress;
  237.         cdb[1] = 0;
  238.         cdb[2] = 0;
  239.         cdb[3] = 0;
  240.         cdb[4] = 3;
  241.         cdb[5] = 0;
  242.         if ((rc = tape_read_cmd(cdb, 6, addr, 3)) != 0)
  243.             return rc;
  244.         return (long)addr[0] << 16 | (long)addr[1] << 8 | addr[2];
  245.     }
  246. }
  247.  
  248. static int
  249. num_result(int ret, long count, long *actual)
  250. {
  251.     if (actual)
  252.         *actual = TapeUndefLength;
  253.     if (ret == MappedError+0)
  254.         return FileMark;
  255.     if (ErrorClass(ret) == SenseKey) {
  256.         if (actual && sense_ptr[0] & VADD)
  257.             *actual = count - int32(sense_ptr+3);
  258.         if (ret == SenseKey+NoSense) {
  259.             if (sense_ptr[2] & EOM)
  260.                 return EndOfTape;
  261.             if (sense_ptr[2] & FM)
  262.                 return FileMark;
  263.         }
  264.     } else if (actual && ret == 0)
  265.         *actual = count;
  266.     return ret;
  267. }
  268.  
  269. int
  270. tape_space(int mode, long nitems, long *actual)
  271. {
  272.     cdb[0] = SeqSpace;
  273.     cdb[1] = mode;
  274.     cdb[2] = nitems >> 16;
  275.     cdb[3] = nitems >> 8;
  276.     cdb[4] = nitems;
  277.     cdb[5] = 0;
  278.     return num_result(tape_cmd(cdb, 6), nitems, actual);
  279. }
  280.  
  281. int
  282. tape_seek(int imed, long blkno)
  283. {
  284.     if (scsiLevel >= 2) {
  285.         cdb[0] = SeqLocate;
  286.         cdb[1] = imed ? 5 : 4;
  287.         cdb[2] = 0;
  288.         cdb[3] = blkno >> 24;
  289.         cdb[4] = blkno >> 16;
  290.         cdb[5] = blkno >> 8;
  291.         cdb[6] = blkno;
  292.         cdb[7] = 0;
  293.         cdb[8] = 0;
  294.         cdb[9] = 0;
  295.         return tape_cmd(cdb, 10);
  296.     } else {
  297.         cdb[0] = SeqSeek;
  298.         cdb[1] = imed ? 1 : 0;
  299.         cdb[2] = blkno >> 16;
  300.         cdb[3] = blkno >> 8;
  301.         cdb[4] = blkno;
  302.         cdb[5] = 0;
  303.         return tape_cmd(cdb, 6);
  304.     }
  305. }
  306.  
  307. static int
  308. rw_result(int ret, long nb, long *actual)
  309. {
  310.     if (actual)
  311.         *actual = TapeUndefLength;
  312.     if (ret == MappedError+0)
  313.         return FileMark;
  314.     if (ErrorClass(ret) == SenseKey) {
  315.         if (actual && sense_ptr[0] & VADD)
  316.             *actual = (blocksize ? blocksize : 1)
  317.                 * (nb - int32(sense_ptr+3));
  318.         if (ret == SenseKey+NoSense) {
  319.             if (sense_ptr[2] & EOM)
  320.                 return EndOfTape;
  321.             if (sense_ptr[2] & FM)
  322.                 return FileMark;
  323.         }
  324.     } else if (actual && ret == 0)
  325.         *actual = (blocksize ? blocksize : 1) * nb;
  326.     return ret;
  327. }
  328.  
  329. int
  330. tape_read(void _far *data, long length, long *actual)
  331. {
  332.     long nb;
  333.     if (!valid_blocksize)
  334.         tape_get_blocksize();
  335.     nb = blocksize ? length / blocksize : length;
  336.     cdb[0] = SeqRead;
  337.     cdb[1] = blocksize ? 1 : 0;
  338.     cdb[2] = nb >> 16;
  339.     cdb[3] = nb >> 8;
  340.     cdb[4] = nb;
  341.     cdb[5] = 0;
  342.     return rw_result(tape_read_cmd(cdb, 6, data, length), nb, actual);
  343. }
  344.  
  345. int
  346. tape_compare(void _far *data, long length, long *actual)
  347. {
  348.     int ret;
  349.     long nb;
  350.     if (!valid_blocksize)
  351.         tape_get_blocksize();
  352.     nb = blocksize ? length / blocksize : length;
  353.     cdb[0] = SeqVerify;
  354.     cdb[1] = blocksize ? 3 : 2;
  355.     cdb[2] = nb >> 16;
  356.     cdb[3] = nb >> 8;
  357.     cdb[4] = nb;
  358.     cdb[5] = 0;
  359.     return rw_result(tape_write_cmd(cdb, 6, data, length), nb, actual);
  360. }    
  361.  
  362. int
  363. tape_verify(long length, long *actual)
  364. {
  365.     int ret;
  366.     long nb;
  367.     if (!valid_blocksize)
  368.         tape_get_blocksize();
  369.     nb = blocksize ? length / blocksize : length;
  370.     cdb[0] = SeqVerify;
  371.     cdb[1] = blocksize ? 1 : 0;
  372.     cdb[2] = nb >> 16;
  373.     cdb[3] = nb >> 8;
  374.     cdb[4] = nb;
  375.     cdb[5] = 0;
  376.     return rw_result(tape_cmd(cdb, 6), nb, actual);
  377. }    
  378.  
  379. int
  380. tape_write(void _far *data, long length, long *actual)
  381. {
  382.     int ret;
  383.     long nb;
  384.     if (!valid_blocksize)
  385.         tape_get_blocksize();
  386.     nb = blocksize ? length / blocksize : length;
  387.     cdb[0] = SeqWrite;
  388.     cdb[1] = blocksize ? 1 : 0;
  389.     cdb[2] = nb >> 16;
  390.     cdb[3] = nb >> 8;
  391.     cdb[4] = nb;
  392.     cdb[5] = 0;
  393.     return rw_result(tape_write_cmd(cdb, 6, data, length), nb, actual);
  394. }
  395.  
  396. static void
  397. cleanup(void)
  398. {
  399.     if (active) {
  400.         while (scsi_wait(&ctrl, sense_ptr, 1) == ComeAgain)
  401.             ;
  402.         active = 0;
  403.     }
  404. }
  405.  
  406. int
  407. tape_buffered_write(void _far *data, long length)
  408. {
  409.     int ret;
  410.  
  411.     if (!valid_blocksize)
  412.         tape_get_blocksize();
  413.  
  414.     if (ctrl == NULL) {
  415.         atexit(cleanup);
  416.         ctrl = scsi_alloc();
  417.     }
  418.  
  419.     active_nb = blocksize ? length / blocksize : length;
  420.  
  421.     cdb[0] = SeqWrite;
  422.     cdb[1] = blocksize ? 1 : 0;
  423.     cdb[2] = active_nb >> 16;
  424.     cdb[3] = active_nb >> 8;
  425.     cdb[4] = active_nb;
  426.     cdb[5] = 0;
  427.  
  428.     ret = scsi_start(ctrl, target, 0, cdb, 6, sense_len, data, length, 0);
  429.     if (ret == ComeAgain)
  430.         active = 1;
  431.     return ret;
  432. }
  433.  
  434. int
  435. tape_buffered_wait(long *actual)
  436. {
  437.     int ret;
  438.  
  439.     if (!active)
  440.         return NoCommand;
  441.     ret = scsi_wait(ctrl, sense_ptr, 1);
  442.     active = 0;
  443.     return rw_result(ret, active_nb, actual);
  444. }
  445.  
  446. int
  447. tape_filemark(int imed, long count, long *actual)
  448. {
  449.     cdb[0] = SeqWriteFilemarks;
  450.     cdb[1] = imed ? 1 : 0;
  451.     cdb[2] = count >> 16;
  452.     cdb[3] = count >> 8;
  453.     cdb[4] = count;
  454.     cdb[5] = 0;
  455.     return num_result(tape_cmd(cdb, 6), count, actual);
  456. }
  457.  
  458. int
  459. tape_setmark(int imed, long count, long *actual)
  460. {
  461.     cdb[0] = SeqWriteFilemarks;
  462.     cdb[1] = imed ? 3 : 2;
  463.     cdb[2] = count >> 16;
  464.     cdb[3] = count >> 8;
  465.     cdb[4] = count;
  466.     cdb[5] = 0;
  467.     return num_result(tape_cmd(cdb, 6), count, actual);
  468. }
  469.  
  470. int
  471. tape_erase(void)
  472. {
  473.     cdb[0] = SeqErase;
  474.     cdb[1] = 1;
  475.     cdb[2] = 0;
  476.     cdb[3] = 0;
  477.     cdb[4] = 0;
  478.     cdb[5] = 0;
  479.     return tape_cmd(cdb, 6);
  480. }
  481.  
  482. long
  483. tape_get_blocksize(void)
  484. {
  485.     unsigned char data [12];
  486.     int rc;
  487.  
  488.     cdb[0] = CmdModeSense;
  489.     cdb[1] = 0;
  490.     cdb[2] = 0;
  491.     cdb[3] = 0;
  492.     cdb[4] = 12;        /* length of parameter list */
  493.     cdb[5] = 0;
  494.  
  495.     if ((rc = tape_read_cmd(cdb, 6, data, 12)) != 0)
  496.         return rc;
  497.     blocksize = (long)data[9] << 16 | (long)data[10] << 8 | data[11];
  498.     valid_blocksize = 1;
  499.     scsi_set_blocksize(target, 0, blocksize);
  500.     return blocksize;
  501. }
  502.  
  503. int
  504. tape_set_blocksize(long size)
  505. {
  506.     unsigned char data [12];
  507.  
  508.     blocksize = size;
  509.     scsi_set_blocksize(target, 0, size);
  510.  
  511.     cdb[0] = CmdModeSelect;
  512.     cdb[1] = 0;
  513.     cdb[2] = 0;
  514.     cdb[3] = 0;
  515.     cdb[4] = 12;        /* length of parameter list */
  516.     cdb[5] = 0;
  517.  
  518.     data[0]  = 0;
  519.     data[1]  = 0;
  520.     data[2]  = 0x10;    /* buffered mode */
  521.     data[3]  = 8;        /* block descriptor length */
  522.  
  523.     data[4]  = 0;        /* density is default */
  524.     data[5]  = 0;
  525.     data[6]  = 0;
  526.     data[7]  = 0;
  527.     data[8]  = 0;
  528.     data[9]  = size >> 16;
  529.     data[10] = size >> 8;
  530.     data[11] = size;
  531.  
  532.     return tape_write_cmd(cdb, 6, data, 12);
  533. }
  534.  
  535. int
  536. tape_speed(int code)
  537. {
  538.     unsigned char data [4];
  539.  
  540.     cdb[0] = CmdModeSelect;
  541.     cdb[1] = 0;
  542.     cdb[2] = 0;
  543.     cdb[3] = 0;
  544.     cdb[4] = 4;        /* length of parameter list */
  545.     cdb[5] = 0;
  546.  
  547.     data[0]  = 0;
  548.     data[1]  = 0;
  549.     data[2]  = 0x10 | code;    /* buffered mode */
  550.     data[3]  = 0;        /* block descriptor length */
  551.  
  552.     return tape_write_cmd(cdb, 6, data, 4);
  553. }
  554.  
  555. int
  556. tape_ready(void)
  557. {
  558.     cdb[0] = CmdTestUnitReady;
  559.     cdb[1] = 0;
  560.     cdb[2] = 0;
  561.     cdb[3] = 0;
  562.     cdb[4] = 0;
  563.     cdb[5] = 0;
  564.     return tape_cmd(cdb, 6);
  565. }
  566.  
  567. int
  568. tape_load(int imed, int retension)
  569. {
  570.     cdb[0] = SeqLoad;
  571.     cdb[1] = imed != 0;
  572.     cdb[2] = 0;
  573.     cdb[3] = 0;
  574.     cdb[4] = retension ? 03 : 01;
  575.     cdb[5] = 0;
  576.     return tape_cmd(cdb, 6);
  577. }
  578.  
  579. int
  580. tape_unload(int imed, int mode)
  581. {
  582.     cdb[0] = SeqLoad;
  583.     cdb[1] = imed != 0;
  584.     cdb[2] = 0;
  585.     cdb[3] = 0;
  586.     cdb[4] = (scsiLevel >= 2) ? mode & 07 : mode & 03;
  587.     cdb[5] = (scsiLevel >= 2) ? 0 : mode & 04 << 6;
  588.     return tape_cmd(cdb, 6);
  589. }
  590.  
  591. void
  592. tape_print_sense(FILE *out, int code)
  593. {
  594.     struct Tape_Extended_Sense *p
  595.         = (struct Tape_Extended_Sense *) sense_ptr;
  596.  
  597.     if (ErrorClass(code) == ErrorClass(MappedError)) {
  598.         fprintf(out, "%s\n", tape_error(code));
  599.         return;
  600.     }
  601.     fprintf(out, "Return code:    %s\n", tape_error(code));
  602.     fprintf(out, "Sense key:    %s\n", senseTab[p->sense_key]);
  603.  
  604.     if (p->filemark || p->end_of_media || p->incorrect_length) {
  605.         fprintf(out, "    ");
  606.         if (p->filemark)
  607.             fprintf(out, "Filemark ");
  608.         if (p->end_of_media)
  609.             fprintf(out, "End-of-media ");
  610.         if (p->incorrect_length)
  611.             fprintf(out, "Incorrect-length ");
  612.         fprintf(out, "\n");
  613.     }
  614.  
  615.     switch (senseMode) {
  616.     case TDC3600:
  617.         fprintf(out, "ERCL+ERCD:    %s\n",
  618.             find_error(tdc3600ercd, p->u.tdc.error));
  619.         fprintf(out, "EXERCD:        %s\n",
  620.             find_error(tdc3600xercd, p->u.tdc.xerror));
  621.         fprintf(out, "    blocks=%ld filemarks=%u remaining=%u\n",
  622.             int24(p->u.tdc.no_blocks),
  623.             int16(p->u.tdc.no_filemarks),
  624.             p->u.tdc.no_remaining);
  625.         fprintf(out, "    recovered=%u underruns=%u marginal=%u\n",
  626.             int16(p->u.tdc.no_recovered),
  627.             int16(p->u.tdc.no_underruns),
  628.             p->u.tdc.no_marginal);
  629.         break;
  630.     case SCSI2:
  631.         fprintf(out, "ASC::        %02X\n", p->u.scsi2.asc);
  632.         fprintf(out, "ASCQ:        %02X\n", p->u.scsi2.ascq);
  633.         fprintf(out, "Description:    %s\n",
  634.             find_error(scsi2asc,
  635.                 p->u.scsi2.asc << 8 | p->u.scsi2.ascq));
  636.         break;
  637.     }
  638. }
  639.