home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / podstawy / dos / archive / tar320c-.exe / SOURCES.ZIP / ASPI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-07  |  23.9 KB  |  767 lines

  1. #include <stdio.h>
  2. #include "pctimer.h"
  3. #if 1
  4. #    include "modern.h"
  5. #    include "define.h"
  6. #    include <string.h>
  7. #endif
  8.  
  9. #define NILTIME 0
  10. #define MINTIME 6 /* ~0.3s */
  11. #define TRESET  (unsigned short)SEC2TICK(3)
  12. #define MIDTIME (unsigned short)SEC2TICK(10)
  13. #define MAXTIME (unsigned short)SEC2TICK(300)
  14. #define HALTCPU
  15.  
  16. #define MAXLEX    8
  17. #define UNKNOWN 255
  18.  
  19. void far (*ASPI_ptr)(void far *) = (void far (*)())0xffff0000L;
  20. extern int ASPI_entry(void far (* far *)());
  21.  
  22. #define HA_INQ      0 /* host adapter inquiry        */
  23. #define GET_TYPE  1 /* get device type               */
  24. #define EXEC_SIO  2 /* execute SCSI I/O command    */
  25. #define ABORT_SRB 3 /* abort SCSI I/O command       */
  26. #define RESET_DEV 4 /* reset SCSI device           */
  27. #define SET_HAP   5 /* set host adapter parameters */
  28. #define GET_DI      6 /* get disk drive information  */
  29.  
  30. #define TAPE      1 /* SCSI device type */
  31.  
  32. #ifndef byte
  33. #    define byte unsigned char
  34. #endif
  35. #define SRBHEAD byte command, status, adapter, flags, reserved[4]
  36. #define MAX_CDB   6  /* Group 0 commands only */
  37. #define MAX_SENCE 14 /* ??? */
  38.  
  39. struct _srbinquiry {
  40.    SRBHEAD, ha_total, ha_type, mgr_id[16], ha_id[16], hap[16];
  41. };
  42. struct _srbgettype {
  43.    SRBHEAD, target, lun, devtype;
  44. };
  45. struct _srbabort {
  46.    SRBHEAD, pointer[4];
  47. };
  48. struct _srbio {
  49.    SRBHEAD, target, lun,
  50.    datalength[4], sencelength, databuffer[4], srblink[4], cdblength,
  51.    adapter_status, target_status, post_routine[4],
  52.    workspace[34], area[MAX_CDB + MAX_SENCE];
  53. };
  54. struct _srbreset {
  55.    SRBHEAD, target, lun, dummy[14],
  56.    adapter_status, target_status, post_routine[4], workspace[34];
  57. };
  58. struct _cdbtape {
  59.    byte opcode, unit, counter[3], control;
  60. };
  61.  
  62. /* SCSI tape opcodes */
  63. #define S0P_TEST   0  /* test unit ready */
  64. #define S0P_REWIND 1
  65. #define S0P_LIMITS 5  /* read block limits */
  66. #define S0P_READ   8
  67. #define S0P_WRITE  10
  68. #define S0P_WFM    16 /* write file mark */
  69. #define S0P_SPACE  17
  70. #define S0P_MODE   21 /* mode select */
  71. #define S0P_ERASE  25
  72.  
  73. /* Transfer direction bits */
  74. #define T_INHERIT 000 /* Command-dependent*/
  75. #define T_READ      010 /* Read from target */
  76. #define T_WRITE   020 /* Write to target  */
  77. #define T_NONE      030 /* No data transfer */
  78.  
  79. #define ASPI_EMPTY    0
  80. #define ASPI_QUEUED    0
  81. #define ASPI_SUCCESS    1
  82. #define ASPI_SENCE    2
  83. #define ASPI_ABORTED    2
  84. #define ASPI_INVALID    0x80 /* illegal request */
  85. #define ASPI_NoHA    0x81 /* invalid host adapter */
  86. #define ASPI_ABSENT    0x82 /* device not installed */
  87. #define SCSI_SENCE    0x20
  88. #define SCSI_SENCEOK    0x20
  89. #define SCSI_RECOVER    0x21
  90. #define SCSI_INVALID    0x25 /* illegal request */
  91. #define SCSI_ATTN    0x26 /* unit attention */
  92. #define SCSI_BLANK    0x28
  93. #define SCSI_ILI    0x35 /* incorrect length indicator */
  94. #define SCSI_EOM    0x36 /* end-of-medium */
  95. #define SCSI_FM     0x37 /* hit file mark */
  96.  
  97. int aspierrno;
  98. struct { byte code; char *text; } aspierrlist[] = {
  99.    { 0x00, "SCSI request in progress"            },
  100.    { 0x01, "SCSI request completed without error"},
  101.    { 0x02, "SCSI request aborted by host"        },
  102.    { 0x04, "SCSI request completed with error"   },
  103.    { 0x08, "Specified Target/LUN is busy"        },
  104.    { 0x11, "Selection timeout"                   },
  105.    { 0x12, "Data over-run/under-run"             },
  106.    { 0x13, "Unexpected Bus Free"                 },
  107.    { 0x14, "Target bus phase sequence failure"   },
  108.    { 0x18, "Reservation conflict"                },
  109.  
  110.    { 0x20, "No sence"          }, /* My codes */
  111.    { 0x21, "Recovered error"   },
  112.    { 0x22, "Not ready"         },
  113.    { 0x23, "Medium error"      },
  114.    { 0x24, "Hardware error"    },
  115.    { 0x25, "Illegal request"   },
  116.    { 0x26, "Unit attention"    },
  117.    { 0x27, "Data protect"      },
  118.    { 0x28, "Blank check"       },
  119.    { 0x29, "Vendor unique"     },
  120.    { 0x2A, "Copy aborted"      },
  121.    { 0x2b, "Aborted command"   },
  122.    { 0x2C, "Equal"             },
  123.    { 0x2d, "Volume overflow"   },
  124.    { 0x2E, "Miscompare"        },
  125.    { 0x2f, "Reserved sence key"},
  126.  
  127.    { 0x35, "Incorrect length"  },
  128.    { 0x36, "End of medium"     },
  129.    { 0x37, "File mark reached" },
  130.  
  131.    { 0x80, "Invalid SCSI request"       }, /* ASPI codes again */
  132.    { 0x81, "Invalid Host Adapter Number"},
  133.    { 0x82, "SCSI device not installed"  },
  134. };
  135.  
  136. char *aspierrmsg(int n)
  137. {
  138.    static char h[16] = "0123456789ABCDEF";
  139.    static char vendor[] = "Vendor unique, class ? code ?h";
  140.    static char other[] = "Error ??h";
  141.    register i;
  142.  
  143.    for (i=0; i<sizeof(aspierrlist)/sizeof(aspierrlist[0]); i++) {
  144.       if (aspierrlist[i].code == n) return aspierrlist[i].text;
  145.    }
  146.    if (n >= 0x70 && n <= 0xff) {
  147.       vendor[21] = n >= 0xf0 ? '0' : h[(n >> 4) & 7];
  148.       vendor[28] = h[n & 15];
  149.       return vendor;
  150.    }
  151.    other[6] = h[(n >> 4) & 15];
  152.    other[7] = h[ n         & 15];
  153.    return other;
  154. }
  155.  
  156. int aspicall(struct _srbio *s, unsigned timeout)
  157. {
  158.    unsigned long t0;
  159.    struct _srbabort sa;
  160.    register unsigned char *p;
  161.  
  162.    *(long *)(s->reserved) = 0L; /* clear reserved field */
  163.    (*ASPI_ptr)((void far *)s);
  164.    if (s->status != ASPI_QUEUED || timeout == 0) goto test;
  165.    for (t0 = pctimer();;) {
  166.      if (s->status != ASPI_QUEUED) goto test;
  167.      if (pctimer() - t0 > timeout) break;
  168.      HALTCPU;
  169.    }
  170.    /* Timeout expired - abort the request */
  171.    sa.command = ABORT_SRB;
  172.    sa.adapter = s->adapter;
  173.    sa.flags   = 0;
  174.    *(long *)sa.reserved = 0L;
  175.    *(void far * far *)sa.pointer = (void far *)s;
  176.    (void)(*ASPI_ptr)((void far *)&sa);
  177.    /* Wait till IO aborted */
  178.    for (t0=pctimer(); 1 >= pctimer()-t0;) HALTCPU;
  179.    if (s->status == ASPI_QUEUED) s->status = ASPI_ABORTED;
  180. test:
  181.    if (s->status & 0x80) return s->status;
  182.    if (s->adapter_status != ASPI_EMPTY) return s->adapter_status;
  183.    if (s->target_status  != ASPI_EMPTY) {
  184.       /* Is sence area information available? */
  185.       if (s->target_status != ASPI_SENCE) return s->target_status;
  186.       if (s->command == EXEC_SIO) {
  187.          p = s->area + s->cdblength;
  188.          /* Take out vendor-unique classes (remap class 0 to 15) */
  189.          if ((*p & 0x70) == 0x00) return *p | 0xf0;
  190.          if ((*p & 0x70) != 0x70) return *p | 0x80;
  191.          /* Take out vendor-unique codes */
  192.          if ((*p & 0x0f) != 0x00) return *p & 0x7f;
  193.          /* Is incorrect length indicator set? */
  194.          if (p[2] & 0x20) return SCSI_ILI;
  195.          /* Is nontrivial sence key available? */
  196.          if (p[2] & 0x0E) return (p[2] & 15) | SCSI_SENCE;
  197.          /* Check for file mark and end-of-medium conditions */
  198.          if (p[2] & 0x80) return SCSI_FM;
  199.          if (p[2] & 0x40) return SCSI_EOM;
  200.          /* Nothing looks like an error */
  201.          return (p[2] & 15) | SCSI_SENCE;
  202.       }
  203.    }
  204.    return s->status;
  205. }
  206.  
  207. #define END_OF_MEDIUM 0x80
  208. #define FIXED_MODE    1
  209. #define NO_RESET      2
  210. #define NO_REWIND     4
  211. #define ERASE         8
  212. #define FM_ON_CLOSE   0x10
  213. #define OPEN_FLAGS    0x1E
  214.  
  215. static struct {
  216.    unsigned long maxblock; unsigned short minblock;
  217.    byte adapter, target, lun, density, flags;
  218. } id = { -1L, 0, 0, 4, 0, 0, 0 };
  219. static long residue;
  220. static byte lastcmd = 0;
  221. static byte ok_to_close = FALSE;
  222. static unsigned to_skip = 0;
  223.  
  224. int aspisio(int cmd, void *buffer, long length, long cmdlen,
  225.             unsigned aspiflags, unsigned cdbflags, unsigned tout)
  226. {
  227.    register k;
  228.    register byte *p;
  229.    struct _srbio s;
  230.  
  231.    s.command = EXEC_SIO;
  232.    s.adapter = id.adapter;
  233.    s.flags   = aspiflags;
  234.    *(long *)(s.reserved) = 0L;
  235.    s.target  = id.target;
  236.    s.lun     = id.lun;
  237.    *(long *)(s.datalength) = length;
  238.    s.sencelength = MAX_SENCE;
  239.    *(void far * far *)(s.databuffer) = (void far *)buffer;
  240.    *(long *)(s.srblink) = 0L;
  241.    s.cdblength = 6; /* Group 0 commands only */
  242.    *(long *)(s.post_routine) = 0xffff0000L;
  243.  
  244.    ((struct _cdbtape *)(s.area))->opcode = lastcmd = cmd;
  245.    ((struct _cdbtape *)(s.area))->unit = (id.lun << 5) | cdbflags;
  246.    ((struct _cdbtape *)(s.area))->counter[0] = (byte)(cmdlen >> 16);
  247.    ((struct _cdbtape *)(s.area))->counter[1] = (byte)(cmdlen >> 8);
  248.    ((struct _cdbtape *)(s.area))->counter[2] = (byte) cmdlen;
  249.    ((struct _cdbtape *)(s.area))->control = 0;
  250.  
  251.    /* Clear sence area */ *(p = s.area + s.cdblength) = 0;
  252.  
  253.    k = aspicall(&s, tout);
  254.    if (k & SCSI_SENCE && k < 0x70) {
  255.       /* Check sence data area */
  256.       if (p[2] & 0x40) id.flags |= END_OF_MEDIUM;
  257.       else             id.flags &= ~END_OF_MEDIUM;
  258.       residue = (p[6] | ((unsigned)p[5] << 8)) |
  259.      ((long)(p[4] | ((unsigned)p[3] << 8)) << 16);
  260.    }
  261.    return k;
  262. }
  263.  
  264. int aspiexec(int cmd, unsigned cdbflags, unsigned tout)
  265. {
  266.    return aspisio(cmd, NULL, 0L, 0L, T_NONE, cdbflags, tout);
  267. }
  268.  
  269. int aspitrans(int wr, void *buffer, unsigned length)
  270. {
  271.    register k;
  272.    unsigned fixed, counter;
  273.  
  274.    if (id.flags & FIXED_MODE) {
  275.       if (length % id.minblock) return (aspierrno=SCSI_ILI, -1);
  276.       counter = length / id.minblock;
  277.       fixed = 1;
  278.    } else {
  279.       if (length < id.minblock || length > id.maxblock)
  280.          return (aspierrno=SCSI_ILI, -1);
  281.       counter = length;
  282.       fixed = 0;
  283.    }
  284.    if (wr) {
  285.       wr = S0P_WRITE; k = T_WRITE;
  286.    } else {
  287.       wr = S0P_READ;  k = T_READ;
  288.    }
  289.    k = aspisio(wr, buffer, (long)length, (long)counter, k, fixed, MAXTIME);
  290.    if (k == ASPI_SUCCESS) return length;
  291.    if (k != SCSI_SENCEOK && k != SCSI_RECOVER && k != SCSI_BLANK &&
  292.        k != SCSI_EOM && k != SCSI_FM) return (aspierrno=k, -1);
  293.    if (!residue) return length;
  294.    aspierrno = k;
  295.    if (fixed) {
  296.       if (residue > 0x10000L/id.minblock) return -1;
  297.       residue *= id.minblock;
  298.    }
  299.    return (unsigned long)residue > length ? -1 : length - (int)residue;
  300. }
  301.  
  302. long aspiinvoke(int cmd, long counter, int flag)
  303. {
  304.    register k;
  305.  
  306.    k = aspisio(cmd, NULL, 0L, counter, T_NONE, flag, MAXTIME);
  307.    if (k == ASPI_SUCCESS) return 0L;
  308.    if (k != SCSI_SENCEOK && k != SCSI_RECOVER && k != SCSI_BLANK &&
  309.        k != SCSI_EOM && k != SCSI_FM) return (aspierrno=k, -0x80000000L);
  310.    if (residue) aspierrno = k;
  311.    return residue;
  312. }
  313.  
  314. int aspirewind(void)
  315. {
  316.    register k;
  317.  
  318.    if ((k=aspiexec(S0P_REWIND,0,MAXTIME)) != ASPI_SUCCESS) {
  319.       if ((k != SCSI_SENCEOK && k != SCSI_EOM && k != SCSI_FM) ||
  320.          !(id.flags & END_OF_MEDIUM)) return (aspierrno=k);
  321.    }
  322.    return ASPI_SUCCESS;
  323. }
  324.  
  325. int aspierase(int lbit)
  326. {
  327.    register k;
  328.  
  329.    k = aspiexec(S0P_ERASE, lbit, MAXTIME);
  330.    if (k!=ASPI_SUCCESS && k!=SCSI_SENCEOK && k!=SCSI_EOM)
  331.       return (aspierrno=k);
  332.    return ASPI_SUCCESS;
  333. }
  334.  
  335. int aspireset(void)
  336. {
  337.    struct _srbreset s;
  338.    unsigned long t0;
  339.    register i;
  340.  
  341.    s.command = RESET_DEV;
  342.    s.adapter = id.adapter;
  343.    s.flags   = 0;
  344.    s.target  = id.target;
  345.    s.lun     = id.lun;
  346.    for (i=0; i<sizeof(s.dummy); i++) s.dummy[i] = 0;
  347.    *(long *)(s.post_routine) = 0xffff0000L;
  348.    *(long *)(s.reserved) = 0L; /* clear reserved field */
  349.    (*ASPI_ptr)((void far *)&s);
  350.    for (t0 = pctimer(); s.status == ASPI_QUEUED;) {
  351.       if (pctimer() - t0 > TRESET) break;
  352.       HALTCPU;
  353.    }
  354.    if (!(s.status & 0x80)) {
  355.       if (s.adapter_status != ASPI_EMPTY) return s.adapter_status;
  356.       if (s.target_status  != ASPI_EMPTY) return s.target_status;
  357.    }
  358.    return s.status;
  359. }
  360.  
  361.  
  362. int aspiread(char *buffer, unsigned length)
  363. {
  364.    register k;
  365.  
  366.    if (!cblock) {
  367.       if      (length < id.maxblock) length = (unsigned)id.maxblock;
  368.       else if (length > id.minblock) length = (unsigned)id.minblock;
  369.    }
  370.    if ((k = aspitrans(0, buffer, length)) == -1) {
  371.       (void)fprintf(stderr, "Tar: ASPI read error: %s\n",
  372.          aspierrmsg(aspierrno));
  373.    }
  374.    return k;
  375. }
  376.  
  377. int aspiwrite(char *buffer, unsigned length)
  378. {
  379.    register k;
  380.  
  381.    if (id.flags & END_OF_MEDIUM && lastcmd == S0P_WRITE) {
  382.       aspierrno = SCSI_EOM; k = 0;
  383.    } else {
  384.       k = aspitrans(1, buffer, length);
  385.    }
  386.    if (k != length) {
  387.       (void)fprintf(stderr, "Tar: ASPI write error: %s\n",
  388.          aspierrmsg(aspierrno));
  389.    }
  390.    return k;
  391. }
  392.  
  393. int aspiback(/* number of 512-byte blocks */ int n)
  394. {
  395.    if (aspiinvoke(S0P_SPACE, -1, 0) != 0L) {
  396.       (void)fprintf(stderr, "Tar: ASPI seek error: %s\n",
  397.          aspierrmsg(aspierrno));
  398.       return 0;
  399.    }
  400.    return n;
  401. }
  402.  
  403. static int GetType(void)
  404. {
  405.    struct _srbgettype s;
  406.  
  407.    s.command = GET_TYPE;
  408.    s.adapter = id.adapter;
  409.    s.target  = id.target;
  410.    s.lun     = id.lun;
  411.    s.flags   = 0;
  412.    *(long *)(s.reserved) = 0L;
  413.    (*ASPI_ptr)((void far *)&s);
  414.    if (s.status == ASPI_SUCCESS) return s.devtype;
  415.    aspierrno = s.status;
  416.    return -1;
  417. }
  418.  
  419. static int HAInquiry(struct _srbinquiry *s, int adapter)
  420. {
  421.    s->command = HA_INQ;
  422.    s->adapter = adapter;
  423.    s->flags   = 0;
  424.    *(long *)(s->reserved) = 0L;
  425.    (*ASPI_ptr)((void far *)s);
  426.    return s->status;
  427. }
  428.  
  429. int aspicount(int devno)
  430. {
  431.    register k;
  432.    struct _srbinquiry s;
  433.    register ha_max;
  434.  
  435.    /* Initialise device description */
  436.    id.maxblock = 0x800000L;
  437.    id.minblock = 1;
  438.    id.flags    = 0;
  439.  
  440.    /* Get number of host adapters */
  441.    if ((k=HAInquiry(&s, 0)) != ASPI_SUCCESS) return k;
  442.    ha_max = s.ha_total;
  443.  
  444.    /* Search for the tape device with given number */
  445.    for (id.adapter = 0; id.adapter < ha_max; id.adapter ++)
  446.       for (id.target = 0; id.target < 8; id.target ++)
  447.          for (id.lun = 0; id.lun < 8; id.lun ++) {
  448.             if ((k = GetType()) == -1) {
  449.                if (aspierrno != ASPI_ABSENT) return aspierrno;
  450.             } else if (k == TAPE) {
  451.                if (devno-- == 0) goto found;
  452.             }
  453.          }
  454.    /* There is no so many tape devices */ return ASPI_ABSENT;
  455. found:
  456.    return ASPI_SUCCESS;
  457. }
  458.  
  459. static int hex(register c)
  460. {
  461.    if       (c>='0' && c<='9') c -= '0';
  462.    else if (c>='A' && c<='F') c -= 'A'-10;
  463.    else if (c>='a' && c<='f') c -= 'a'-10;
  464.    else c = ERROR;
  465.    return c;
  466. }
  467.  
  468. int aspiparse(char *s)
  469. {
  470.    static char already[] = "tape format already defined";
  471.    static struct { unsigned short nqic, code; } qiclist[] = {
  472.       {11,4}, {120,15}, {150,16}, {320,17}, {525,17}, {1350,18}
  473.    };
  474.    char lex[MAXLEX+1], *errmsg;
  475.    register i, k; register char *p;
  476.  
  477.    for (i=0; i<sizeof(lex) && *s!='.'; i++) {
  478.       if (*s == '\0' || *s == ':' || *s == ';' || *s == ',') goto test_name;
  479.       lex[i] = *s++;
  480.    }
  481.    return FALSE;
  482. test_name:
  483.    lex[i] = '\0';
  484.    if ((lex[0] & ~('z'^'Z')) != 'A' || strnicmp(lex,"ASPI",4)) return FALSE;
  485.    if (lex[4]!='\0' && stricmp(lex+4,"MGR$") && stricmp(lex+4,"TAPE"))
  486.       return FALSE;
  487.  
  488.    to_skip       = 0;
  489.    ok_to_close = FALSE;
  490.    id.maxblock = 0x800000L;
  491.    id.minblock = 1;
  492.    id.adapter  = UNKNOWN;
  493.    id.target   = UNKNOWN;
  494.    id.lun       = UNKNOWN;
  495.    id.density  = 0;
  496.    id.flags    = 0;
  497.  
  498.    if (*s) {
  499.       while (*++s) {
  500.          for (i=0; i<=MAXLEX; ++i, s++) {
  501.             if      (*s >= 'A' && *s <= 'Z') lex[i] = *s | ('z'^'Z');
  502.             else if (*s >= 'a' && *s <= 'z') lex[i] = *s;
  503.             else break;
  504.          }
  505.          if (i < 1 || i > MAXLEX) {
  506.             errmsg = "device parameter error"; goto error;
  507.          }
  508.          lex[i] = '\0'; /* for diagnostic printing */
  509.          if (!strncmp("norewind", lex, i)) {
  510.             if (to_skip || id.flags & ERASE) goto mutual;
  511.             id.flags |= NO_REWIND;
  512.          } else if (!strncmp("erase", lex, i)) {
  513.             if (to_skip || id.flags & NO_REWIND) goto mutual;
  514.             id.flags |= ERASE;
  515.          } else if (!strncmp("qic", lex, i)) {
  516.             if (id.density) {
  517.                errmsg = already; goto error;
  518.             }
  519.             if (*s == '-') {
  520.                ++s;
  521.             } else {
  522.                if (*s == ':') ++s;
  523.                if (*s == '=') ++s;
  524.             }
  525.             for (k=0, i=0; i<5 && *s>='0' && *s<='9'; ++s, i++)
  526.                k = (*s - '0') + 10*k;
  527.             if (i < 5)
  528.                for (i=0; i<dimof(qiclist); i++)
  529.                   if (qiclist[i].nqic == k) {
  530.                      id.density = qiclist[i].code; break;
  531.                   }
  532.             if (!id.density) {
  533.                errmsg = "invalid QIC number"; goto error;
  534.             }
  535.          } else {
  536.             if (*s == ':') ++s;
  537.             if (*s == '=') ++s;
  538.             if (strncmp("adapter", lex, i) == 0) {
  539.                if (*s<'0' || *s>'7') {
  540.                   errmsg = "invalid adapter number"; goto error;
  541.                }
  542.                id.adapter = *s++ & 7;
  543.             } else if (strncmp("target", lex, i) == 0) {
  544.                if (*s<'0' || *s>'7') {
  545.                   errmsg = "invalid target number"; goto error;
  546.                }
  547.                id.target = *s++ & 7;
  548.             } else if (strncmp("lun", lex, i) == 0) {
  549.                if (*s<'0' || *s>'7') {
  550.                   errmsg = "invalid LUN number"; goto error;
  551.                }
  552.                id.lun = *s++ & 7;
  553.             } else if (!strncmp("skip", lex, i)) {
  554.                if (id.flags & (ERASE|NO_REWIND)) goto mutual;
  555.                for (to_skip=0, i=0; i<5 && *s>='0' && *s<='9'; ++i, s++) {
  556.                   to_skip = (*s - '0') + 10*to_skip;
  557.                }
  558.             } else if (!strncmp("code", lex, i) ||
  559.                        !strncmp("density", lex, i)) {
  560.                id.density = 0; p = s;
  561.                if (*p == '0') ++p;
  562.                if ((*p | ('z'^'Z')) == 'x') {
  563.                   for (i=0, s=p+1; i<2; ++s, i++) {
  564.                      if ((k = hex(*s)) == ERROR) break;
  565.                         id.density = k | (id.density << 4);
  566.                      }
  567.                } else {
  568.                   while (hex(*p)!=ERROR) ++p;
  569.                   if ((*p | ('z'^'Z')) == 'h') {
  570.                      for (i=0; i<2; ++s, i++) {
  571.                        if ((k = hex(*s)) == ERROR) break;
  572.                        id.density = k | (id.density << 4);
  573.                      }
  574.                      if ((*s | ('z'^'Z')) == 'h') ++s;
  575.                   } else {/* decimal code */
  576.                      for (i=0; i<4 && *s>='0' && *s<='9'; ++i, s++) {
  577.                         id.density = (*s - '0') + 10*id.density;
  578.                      }
  579.                   }
  580.                }
  581.                if (!i || ~255 & id.density) {
  582.                   errmsg = "invalid density code"; goto error;
  583.                }
  584.             } else {
  585.                (void)fprintf(stderr,"Tar: unknown parameter \'%s\'\n",lex);
  586.                return ERROR;
  587.             }
  588.          }
  589.          if (*s == '\0') break;
  590.          if (*s != ',' && *s != ':' && *s != '.') {
  591.             (void)fprintf(stderr,"Tar: invalid character after \'%s\'\n",lex);
  592.             return ERROR;
  593.          }
  594.       }
  595.    }
  596.    if (ASPI_entry((void far *)&ASPI_ptr) != 0) {
  597.       errmsg = "no ASPI manager found"; goto error;
  598.    }
  599.    if (setdrive ||
  600.       (id.adapter==UNKNOWN && id.target==UNKNOWN && id.lun==UNKNOWN)) {
  601.       if (id.adapter!=UNKNOWN || id.target!=UNKNOWN || id.lun!=UNKNOWN) {
  602.          errmsg = "both device number and SCSI parameters specified";
  603.          goto error;
  604.       }
  605.       if ((k=aspicount(ndrive)) != ASPI_SUCCESS) {
  606.          errmsg = k!=ASPI_ABSENT ? aspierrmsg(k) :
  607.                   "there is no so many tape devices" ;
  608.          goto error;
  609.       }
  610.    } else {
  611.       if (id.target == UNKNOWN) {
  612.          errmsg = "unknown target number"; goto error;
  613.       }
  614.       if (id.adapter == UNKNOWN) id.adapter = 0;
  615.       if (id.lun     == UNKNOWN) id.lun = 0;
  616.       if ((k=GetType()) != TAPE) {
  617.          errmsg = k == -1 ? aspierrmsg(k) : "not a tape device specified";
  618.          goto error;
  619.       }
  620.    }
  621.    if (v_flag) {
  622.       struct _srbinquiry s;
  623.       if (HAInquiry(&s, id.adapter) != ASPI_SUCCESS) goto reported;
  624.  
  625.       for (i=16; i && (s.mgr_id[i-1]=='\0' || s.mgr_id[i-1]==' '); i--);
  626.       for (k=16; k && (s.ha_id [k-1]=='\0' || s.ha_id [k-1]==' '); k--);
  627.       if (!i && !k) goto reported;
  628.  
  629.       (void)fprintf(myout, "Tar: ");
  630.       if (i) {
  631.          (void)fprintf(myout, "ASPI manager: <%-.*s>", i, s.mgr_id);
  632.          if (k) (void)fprintf(myout, ", ");
  633.       }
  634.       if (k) {
  635.          (void)fprintf(myout, "SCSI adapter: <%-.*s>", k, s.ha_id);
  636.       }
  637.       (void)fprintf(myout, "\n");
  638. reported:;
  639.    }
  640.    if (a_flag && !(id.flags & NO_REWIND)) id.flags |= FM_ON_CLOSE;
  641.    return TRUE;
  642. mutual:
  643.    errmsg = "\'erase\', \'norewind\' and \'skip\' are mutaully exclusive";
  644. error:
  645.    (void)fprintf(stderr, "Tar: %s\n", errmsg);
  646.    return ERROR;
  647. }
  648.  
  649. int aspisetmode(long bsize, int speed, int bm, int pf)
  650. {
  651.    unsigned char b[12];
  652.  
  653.    b[1] = b[0] = 0;
  654.    b[2] = (unsigned char)speed;
  655.    if (bm) b[2] |= 16;
  656.    b[3] = 8; /* block descriptor length */
  657.  
  658.    b[4] = id.density;
  659.    b[7] = b[6] = b[5] = 0; /* whole tape */
  660.    b[8] = 0; /* reserved */
  661.    b[ 9] = (unsigned char)(255 & (bsize >> 16));
  662.    b[10] = (unsigned char)(255 & (bsize >> 8));
  663.    b[11] = (unsigned char)(255 &  bsize);
  664.    return aspisio(S0P_MODE, b, 12L, 12L, T_WRITE, (pf ? 16 : 0), MINTIME);
  665. }
  666.  
  667. int aspistart(void)
  668. {
  669.    register k;
  670.    unsigned char b[6];
  671.    extern void printbs(int);
  672.  
  673.    if (!(id.flags & (NO_RESET|NO_REWIND)) && id.density != 127) {
  674.       (void)aspireset();
  675.       /* Clear 'unit attension' condition */
  676.       for (k=0; k<7; k++) {
  677.          if (aspiexec(S0P_TEST, 0, MINTIME) != SCSI_ATTN) break;
  678.       }
  679.    }
  680.    if (!(id.flags & NO_REWIND)) {
  681.       if (aspirewind() != ASPI_SUCCESS) {
  682.          if (aspierrno != SCSI_ATTN) goto error;
  683.          if (aspirewind() != ASPI_SUCCESS) goto error;
  684.       }
  685.       if (id.flags & ERASE) {
  686.          if (aspierase(1) != ASPI_SUCCESS) goto error;
  687.          if (aspirewind() != ASPI_SUCCESS) goto error;
  688.       }
  689.    }
  690.    /* Read block limits */
  691.    k = aspisio(S0P_LIMITS, b, 6L, 0L, T_READ, 0, MINTIME);
  692.    if (k == ASPI_SUCCESS || k == SCSI_SENCEOK || k == SCSI_EOM) {
  693.       id.minblock = b[5] | ((unsigned)b[4] << 8);
  694.       id.maxblock = b[3] | ((unsigned)b[2] << 8) | ((unsigned long)b[1]<<16);
  695.       if (!id.maxblock) id.maxblock = 0x800000L;
  696.  
  697.       if (id.minblock != id.maxblock) {
  698.          id.flags &= ~FIXED_MODE;
  699.          if (cblock) {
  700.             if (k < id.minblock || k > id.maxblock) {
  701.                (void)fprintf(stderr,
  702.                   "Tar: blocksize is out of hardware limits (%d - %ld)\n",
  703.                   id.minblock / BLKSIZE, id.maxblock / BLKSIZE);
  704.                return ERROR;
  705.             }
  706.          } else if (c_flag) {
  707.             printbs(cblock = id.maxblock < BLKSIZE*MAXBLOCK ?
  708.                        (int)(id.maxblock/BLKSIZE) : MAXBLOCK);
  709.          }
  710.       } else {
  711.          id.flags |= FIXED_MODE;
  712.          if (id.minblock % BLKSIZE || id.minblock > BLKSIZE*MAXBLOCK) {
  713.             (void)fprintf(stderr,
  714.                "Tar: hardware blocksize %ld bytes is not suitable for tar\n",
  715.                id.minblock);
  716.          }
  717.          if (cblock) {
  718.             if ((cblock*BLKSIZE) % id.minblock) {
  719.                (void)fprintf(stderr,
  720.                   "Tar: blocksize must be multiple of %ld\n",
  721.                   id.minblock/BLKSIZE);
  722.             }
  723.          } else {
  724.             printbs(cblock = id.minblock / BLKSIZE);
  725.          }
  726.       }
  727.    } else {
  728.       if (cblock) {
  729.          id.maxblock = id.minblock = BLKSIZE*cblock;
  730.          id.flags |= FIXED_MODE;
  731.       } else {
  732.          id.maxblock = BLKSIZE*MAXBLOCK;
  733.          id.minblock = BLKSIZE;
  734.          id.flags &= ~FIXED_MODE;
  735.       }
  736.    }
  737.    if (id.density!=0 && id.density != 127) {
  738.       for (k=4; k--;) {
  739.          if (aspisetmode((long)(BLKSIZE*cblock), 0, k&2, k&1)
  740.             != SCSI_INVALID) break;
  741.       }
  742.    }
  743.    ok_to_close = TRUE;
  744.    if (to_skip) {
  745.       if (aspisio(S0P_SPACE, NULL, 0L, (long)to_skip, T_NONE, 1, MAXTIME)
  746.          != ASPI_SUCCESS) goto error;
  747.    }
  748.    return 0;
  749. error:
  750.    (void)fprintf(stderr, "Tar: %s\n", aspierrmsg(aspierrno));
  751.    return ERROR;
  752. }
  753.  
  754. void aspiend(void)
  755. {
  756.    if (!ok_to_close) return;
  757.    if (id.flags & FM_ON_CLOSE || lastcmd == S0P_WRITE) {
  758.       if (aspiinvoke(S0P_WFM,
  759.             ((id.flags & (FM_ON_CLOSE|NO_REWIND)) == FM_ON_CLOSE ? 1L : 0L),
  760.             0) != 0L) goto error;
  761.    }
  762.    if (id.flags & NO_REWIND) return;
  763.    if (aspirewind() == ASPI_SUCCESS) return;
  764. error:
  765.    (void)fprintf(stderr, "Tar: %s\n", aspierrmsg(aspierrno));
  766. }
  767.