home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / DISK / ASPIPAT.ZIP / ASPI.C next >
Encoding:
C/C++ Source or Header  |  1992-01-26  |  30.2 KB  |  1,219 lines

  1. #ident "$Id: aspi.c,v 1.1 1992/01/15 01:14:12 chris Exp $"
  2.  
  3. #include <stdio.h>
  4. #include <fcntl.h>
  5. #include <dos.h>
  6. #include <string.h>
  7. #include <malloc.h>
  8. #include <ctype.h>
  9. #include <errno.h>
  10.  
  11. /*
  12.  * $Log: aspi.c,v $
  13.  * Revision 1.1  1992/01/15  01:14:12  chris
  14.  * Initial revision
  15.  *
  16.  *
  17.  *
  18.  * chris@alderan.sdata.de
  19.  */
  20.  
  21. #define DWORD unsigned long
  22. #ifndef TAPE_ID
  23. #define TAPE_ID "0:4:0"
  24. #endif
  25.  
  26. #include "aspi.h"
  27. #include "scsi.h"
  28. #include "scsierr.h"
  29.  
  30. #ifndef CTCTRL
  31. #include "tar.h"
  32. #endif
  33.  
  34. static char *aspi_c_id = "$Id: aspi.c,v 1.1 1992/01/15 01:14:12 chris Exp $";
  35.  
  36. void aspiinit();
  37. extern int errno;
  38.  
  39.  
  40. /*
  41.  * The complete scsi address of our tape device
  42.  */
  43. int adapter_id, scsi_tape_id, lun_id;
  44.  
  45. /*
  46.  * Because all the scsi functions start with:
  47.  * SCSIfunc(adapter_id, scsi_tape_id, lun, .......)
  48.  * .. we define a macro "TARGET", so that we can write SCSIfunc(TARGET, ...);
  49.  */
  50. #define TARGET adapter_id, scsi_tape_id, lun_id
  51.  
  52. #ifndef CTCTRL
  53.  
  54. /* Flags to for use with the streamer (detected at aspiopen()) */
  55. static int aspifile, no_rewind;
  56.  
  57. /* This holds the max., and min. recordsize, the streamer can deal with */
  58. static blocklimit lim;
  59. static long recsize;    /* the record size to use */
  60. static int logrec;      /* log2(recordsize) */
  61. static long apos;       /* this holds the current archive file pointer */
  62. static int write_file_mark_on_close;
  63. static int end_of_medium;
  64. static unsigned char rsense[14]; /* array for scsi-sense-data */
  65.  
  66. /*
  67.  * The next two functions are called when you open a file.
  68.  * They check if the filename specifies the scsi-tape.
  69.  * The filenames used for that are "/dev/ct" - "rewind cartridge tape"
  70.  * and "/dev/nrct" - "no rewind cartridge tape" (no rewind on close)
  71.  * I just choose those names "/dev/ct" and "/dev/nrct" because the
  72.  * filenames are unusual to exist on a MSDOS filesystem and also because
  73.  * I'm used to them from my ix386. Anyway, there are no other dependencies
  74.  * on those names in the whole program. So, if you prefer to change the
  75.  * names to "/dev/rmt0" or whatever, just change them !
  76.  * As you can see in aspicreate() and aspiopen(), I still open a
  77.  * MSDOS-output-dummy-file. "nul:" is kind of /dev/null for MSDOS
  78.  * and I had to do this because the MSDOS code from tar still
  79.  * does some operations on this file like setmode(stream) etc. and
  80.  * I was too lazy to change the code in tar. So, with this they
  81.  * may do setmode()'s on the null-device as long as they want :-)
  82.  */
  83.  
  84.  
  85. /*
  86.  * Create an archive file
  87.  */
  88.  
  89. aspicreat(path, mode)
  90. char *path;
  91. int mode;
  92. {
  93.   end_of_medium = 0;
  94.  
  95.   if ( !strcmp(path, "/dev/ct") )  {
  96.     apos = 0l;
  97.     no_rewind = 0;
  98.     aspiinit();
  99.     write_file_mark_on_close = 1;
  100.     return (aspifile=creat("NUL", mode));
  101.   } else if ( !strcmp(path,"/dev/nrct") )  {
  102.     apos = 0l;
  103.     no_rewind = 1;
  104.     aspiinit();
  105.     write_file_mark_on_close = 1;
  106.     return (aspifile=creat("NUL", mode));
  107.   }
  108.   aspifile = -1;
  109.   return creat(path, mode);
  110. }
  111.  
  112. /*
  113.  * Open an archive file
  114.  */
  115.  
  116. aspiopen(path, oflag, mode)
  117. char *path;
  118. int oflag;
  119. int mode;
  120. {
  121.   end_of_medium = 0;
  122.  
  123.   if ( !strcmp(path, "/dev/ct") )  {
  124.     apos = 0l;
  125.     no_rewind = 0;
  126.     aspiinit();
  127.     if ( (oflag & O_WRONLY) || (oflag & O_RDWR) )
  128.       write_file_mark_on_close = 1;
  129.     else write_file_mark_on_close = 0;
  130.     return (aspifile=open("NUL", oflag, mode));
  131.   } else if ( !strcmp(path,"/dev/nrct") )  {
  132.     apos = 0l;
  133.     no_rewind = 1;
  134.     aspiinit();
  135.     if ( (oflag & O_WRONLY) || (oflag & O_RDWR) )
  136.       write_file_mark_on_close = 1;
  137.     else write_file_mark_on_close = 0;
  138.     return (aspifile=open("NUL", oflag, mode));
  139.   }
  140.   aspifile = -1;
  141.   return open(path, oflag, mode);
  142. }
  143.  
  144.  
  145. /*
  146.  * So, all the other functions now just check if (fileds == aspifile)
  147.  * and do redirect the opereation to the tape. Otherwise they just
  148.  * hand the request to the original function (e.g aspiread()->read() etc.).
  149.  */
  150.  
  151.  
  152. /*
  153.  * Read data from an archive file
  154.  */
  155.  
  156. aspiread(fileds, buf, nbyte)
  157. int fileds;
  158. char *buf;
  159. int nbyte;
  160. {
  161.   int i;
  162.   unsigned int *u;
  163.  
  164.   if ( fileds == aspifile )  {
  165.     u = ( unsigned int * ) &nbyte;    /* Hack,  I know */
  166.     if ( nbyte % ( int ) recsize )  {
  167.       ( void ) fprintf(stderr,
  168.                      "aspiread: Illegal blocklen for tape: %u\n", nbyte);
  169.       ( void ) aspiclose(fileds);
  170.       exit(EX_SYSTEM);
  171.     }
  172.     i = SCSIRead(TARGET, buf, ( long ) *u, logrec, 0, 1, rsense);
  173.     if ( i )  {  /* If any error ... */
  174.       unsigned bytes_read;
  175.  
  176.       if ( i == E$BlankCheck )  {  /* EEOM  (early end of medium) */
  177.         errno = ENOSPC;
  178.         if ( (rsense[2] & 0x40) && (rsense[0] &0x80) ) {
  179.           /* compute the number of bytes read */
  180.           bytes_read =  *u - ((rsense[6]+(rsense[5]<<8))<<logrec);
  181.           apos += ( long ) bytes_read;
  182.           return ( int ) bytes_read;
  183.         } else return 0;
  184.       } else if ( (i==E$Medium) && (rsense[2] & 0x40) && (rsense[0] & 0x80) ) {
  185.         errno = ENOSPC;
  186.         bytes_read =  *u - ((rsense[6]+(rsense[5]<<8))<<logrec);
  187.         apos += ( long ) bytes_read;
  188.         return ( int ) bytes_read;
  189.       } else  {
  190.         ( void ) fprintf(stderr,"aspiread: errno: %d\n", i);
  191.         ( void ) aspiclose(fileds);
  192.         exit(EX_SYSTEM);
  193.       }
  194.     }
  195.     apos += ( long ) *u;
  196.     return nbyte;
  197.   }
  198.   return read(fileds, buf, nbyte);
  199. }
  200.  
  201. /*
  202.  * Write data to an archive file
  203.  */
  204.  
  205. aspiwrite(fileds, buf, nbyte)
  206. int fileds;
  207. char *buf;
  208. int nbyte;
  209. {
  210.   int i;
  211.   unsigned int *u;
  212.  
  213.  
  214.   if ( fileds == aspifile )  {
  215.  
  216.     if ( end_of_medium )  {
  217.      /*
  218.       * This only happens when an end_of_medium condition was detected
  219.       * at the previous aspiwrite() call but all bytes were written to
  220.       * the tape anyway. In this case we don't make anymore attempts to
  221.       * write to the tape but return an ENOSPC error and set the size
  222.       * of transfered bytes to 0
  223.       */
  224.       errno = ENOSPC;
  225.       return 0;
  226.     }
  227.  
  228.     u = ( unsigned int * ) &nbyte;     /* Hack , i know */
  229.  
  230.     if ( nbyte % ( int ) recsize )  {
  231.       ( void ) fprintf(stderr,
  232.                       "aspiwrite: Illegal blocklen for tape: %u\n", nbyte);
  233.       ( void ) aspiclose(fileds);
  234.       exit(EX_SYSTEM);
  235.     }
  236.  
  237.     i = SCSIWrite(TARGET, buf, ( long ) *u, logrec, 1, rsense);
  238.  
  239.     if ( i == E$EndOfMedium )  {
  240.       unsigned int bytes_read;
  241.  
  242.       end_of_medium = 1;
  243.       if ( (rsense[0] & 0x80) && (rsense[6] || rsense[5]) )  {
  244.         /* return the real number of bytes that were written to the tape */
  245.         errno = ENOSPC;
  246.         bytes_read =  *u - ((rsense[6]+(rsense[5]<<8))<<logrec);
  247.         apos += ( long ) bytes_read;
  248.         return ( int ) bytes_read;
  249.       } else i = 0; /* do not return an error if all bytes were written */
  250.     }
  251.     if ( i )  { /* any other error we can't recover */
  252.       ( void ) fprintf(stderr,"aspiwrite: errno: %d\n", i);
  253.       ( void ) aspiclose(fileds);
  254.       exit(EX_SYSTEM);
  255.     }
  256.     apos += ( long ) *u;
  257.     return nbyte;
  258.   }
  259.   return write(fileds, buf, nbyte);
  260. }
  261.  
  262. /*
  263.  * close an archive file
  264.  */
  265.  
  266. aspiclose(fileds)
  267. int fileds;
  268. {
  269.   int i;
  270.  
  271.   if ( fileds == aspifile )  {
  272.     /* first, write a filemark ! */
  273.     if ( write_file_mark_on_close && (!end_of_medium) )
  274.       if ( (i=SCSIWriteFilemarks(TARGET, 1l, 0, 0, 0)) )
  275.         ( void ) fprintf(stderr,"aspiclose: Error writing filemark\n");
  276.     /* then rewind the tape if we have to */
  277.     if ( ! no_rewind )  {
  278.       if ( (i=SCSIRewind(TARGET, 0, 0)) )
  279.         ( void ) fprintf(stderr,"aspiclose: Error rewinding the tape\n");
  280.     } else if ( ! write_file_mark_on_close )  {
  281.      /*
  282.       * This means we've been reading an archive on a "/dev/nrct" tape.
  283.       * In this case we have seek over the filemark at the end of the
  284.       * archive.
  285.       */
  286.       if ( (i=SCSISpace(TARGET, 1, 1l, 0))  )
  287.         ( void ) fprintf(stderr,"aspiclose: Error seeking filemark\n");
  288.     }
  289.     apos = 0l;
  290.   }
  291.   return close(fileds);
  292. }
  293.  
  294. /*
  295.  * Seek on the archive file
  296.  */
  297.  
  298. long aspilseek(fileds, offset, whence)
  299. int fileds;
  300. long offset;
  301. int whence;
  302. {
  303.   int i;
  304.   long newpos;
  305.  
  306.   if ( fileds == aspifile )  {
  307.    /*
  308.     * NOTE: seeking backwards is not supported by every streamer.
  309.     * The Archive Viper 2150S does, but I don't know about others.
  310.     */
  311.     switch ( whence )  {
  312.     case SEEK_SET:
  313.       newpos = offset;
  314.       break;
  315.     case SEEK_CUR:
  316.       newpos = apos + offset;
  317.       break;
  318.     default:
  319.       ( void ) fprintf(stderr, "aspilseek: mode %d not supported\n", whence);
  320.       ( void ) aspiclose(fileds);
  321.       exit(EX_SYSTEM);
  322.       break;
  323.     }
  324.     if ( newpos % recsize )  {
  325.       ( void ) fprintf(stderr,
  326.            "aspilseek: can't seek to a non-block-boundary position (%ld)\n",
  327.                                                                      newpos);
  328.       ( void ) aspiclose(fileds);
  329.       exit(EX_SYSTEM);
  330.     }
  331.     if ( (i=SCSISpace(TARGET, 0, (newpos-apos)>>logrec, 0)) )  {
  332.       ( void ) fprintf(stderr, "aspilseek: SCSISpace retuned errno %d\n", i);
  333.       ( void ) aspiclose(fileds);
  334.       exit(EX_SYSTEM);
  335.     }
  336.     apos = newpos;
  337.     return newpos;
  338.   }
  339.   return lseek(fileds, offset, whence);
  340. }
  341.  
  342. #endif  /* CTCTRL */
  343.  
  344. /*
  345.  * Here we start with all that aspi stuff !!!
  346.  * --------------------------------------------
  347.  * the way we get the entrypoint of the aspi - module is quite strange,
  348.  * but anyway ..
  349.  */
  350.  
  351. /*
  352.  * This will be the function for all aspi requests, it gets
  353.  * initialized at aspiinit() and called from aspirequest()
  354.  */
  355.  
  356. void (far *aspi)(void far *) = (void far *) 0;
  357.  
  358.  
  359. /*
  360.  * Initialize aspi and the tape device
  361.  */
  362.  
  363. void aspiinit()
  364. {
  365.   int h,i;
  366.   long l;
  367.   union REGS inregs;
  368.   union REGS outregs;
  369.   char *getenv(), *tapeid;
  370.  
  371.   if ( (h=open("SCSIMGR$",0)) == -1 )  {
  372.     perror("Opening ASPI Manager");
  373.     exit(1);
  374.   }
  375.  
  376. /*
  377.  * This is an ioctl(READ) to the "SCSIMGR$".
  378.  * It returns the entrypoint of the aspi-module (far pointer)
  379.  * in the 4 bytes, pointed to by the dx register.
  380.  */
  381.  
  382.   inregs.x.ax = 0x4402;
  383.   inregs.x.dx = ( int ) &aspi;
  384.   inregs.x.cx = 4;
  385.   inregs.x.bx = h;
  386.   intdos(&inregs, &outregs);
  387.  
  388.  /*
  389.   * Now find out on which device we have to operate
  390.   */
  391.   tapeid = getenv("TAPEID");
  392.   if ( !tapeid ) tapeid = TAPE_ID;
  393.   if ( (tapeid[1] != ':') || (tapeid[3] != ':') ||
  394.     (!isdigit(tapeid[0])) || (!isdigit(tapeid[2])) || (!isdigit(tapeid[4])) ) {
  395.     ( void ) fprintf(stderr,"aspiinit: Illegal TAPEID: \"%s\"\n", tapeid);
  396.     exit(1);
  397.   } else  {
  398.     adapter_id = tapeid[0] - '0';
  399.     scsi_tape_id = tapeid[2] - '0';
  400.     lun_id = tapeid[4] - '0';
  401.   }
  402.  
  403. #ifndef CTCTRL
  404.  
  405. /*
  406.  * Now, check the device ...
  407.  */
  408.   if ( (i=GetDeviceTyp( TARGET )) < 0 )  {
  409.     ( void ) fprintf(stderr,
  410.              "aspiinit: Can't determine type of device \"%s\"\n", tapeid);
  411.     ( void ) fprintf(stderr,"aspiinit: GetDeviceTyp() returned errno %d\n", i);
  412.     exit(EX_SYSTEM);
  413.   } else if ( i != 1 )  {
  414.     ( void ) fprintf(stderr,"aspiinit: device \"%s\" is not a streamer !\n",
  415.                                                                    tapeid);
  416.     ( void ) fprintf(stderr,"the typ returned by GetDeviceTyp was %d\n",i);
  417.     exit(EX_SYSTEM);
  418.   }
  419.  
  420. /*
  421.  * Now get the max. and min. recordsize for the streamer
  422.  */
  423.   if ( (i=SCSIReadBlockLimits(TARGET, &lim, 0)) != E$NoErr )  {
  424.     ( void ) fprintf(stderr,"aspiinit: Can't read blocklimits. errno %d\n", i);
  425.     exit(EX_SYSTEM);
  426.   }
  427.  
  428. /*
  429.  * *** FIXME ***
  430.  * I don't really know how to handle this. What I do is, check if we have
  431.  * fixed record size (lim.max == lim.min), if this is not true, I don't
  432.  * really know which record size I should take. For now I try 512 bytes,
  433.  * and if 512 is not in range I try lim.min. This is probably not the
  434.  * way to do it. Let me know if you know better.
  435.  * chris@alderan.sdata.de
  436.  */
  437.  
  438.   if ( lim.max == lim.min ) recsize = lim.max;
  439.   else if ( (lim.min <= 512) && (lim.max>=512) ) recsize = 512;
  440.   else recsize = lim.min;
  441.  
  442.   l = recsize; logrec = 0;
  443.   while ( (l>>=1) ) ++logrec;   /* logrec = log2(recsize) */
  444.  
  445. #endif /* CTCTRL */
  446.  
  447. }
  448.  
  449. /*
  450.  * This is the function that we call for all out aspi-requests.
  451.  * The function simply takes our requestblock and hands it to
  452.  * aspi() (the real aspi request function) and then it polls
  453.  * and waits for the request to finish.
  454.  */
  455.  
  456. int aspireq(srb)
  457. void *srb;
  458. {
  459.   int cnt;
  460.  
  461.   struct _srbinquiry *s;
  462.   s = ( struct _srbinquiry *) srb;
  463.   aspi(s);
  464.   cnt = 10;
  465.   while ( cnt-- ) while ( ! s->h.status )  ;   /* POLL ! */
  466.   if ( s->h.status == 1 ) return E$NoErr;
  467.   return E$AspiErr;
  468. }
  469.  
  470. /*
  471.  * The following two commandos are supported directly by the ASPI module
  472.  * and do not require the construction of a SCSI-CCB.
  473.  */
  474.  
  475. int HostAdapterInquiry(inq)
  476. aspiinquiry *inq;
  477. {
  478.   struct _srbinquiry *srb;
  479.   int i;
  480.  
  481.   /* allocate a SCSI Request Block (SRB) in the lower 1 MB */
  482.  
  483.   if ( (srb=calloc(sizeof(struct _srbinquiry), 1)) == ( char *) 0 )
  484.     return(E$NoMem);
  485.  
  486.   srb->h.cmd = 0;           /* Host Adapter Inquiry */
  487.   srb->h.adapter = inq->adapter_num;
  488.  
  489.   /* issue the request */
  490.   if ( (i=aspireq(srb)) )  {             /* if error status */
  491.     free(srb);
  492.     return(i);
  493.   }
  494.  
  495.   inq->adapters = srb->adapters;   /* number of hostadapters */
  496.   inq->target_id = srb->target_id;
  497.  
  498.   for(i=0; i<16; ++i) inq->manager_id[i] = srb->manager_id[i];
  499.   inq->manager_id[16] = '\0';
  500.  
  501.   for(i=0; i<16; ++i) inq->adapter_id[i] = srb->adapter_id[i];
  502.   inq->adapter_id[16] = '\0';
  503.  
  504.   free(srb);
  505.   return(E$NoErr);
  506. }
  507.  
  508. /*
  509.  * GetDeviceTyp: The returned typ corresponds to the typ of an
  510.  *               SCSI-Inquiry command.
  511.  */
  512.  
  513. int GetDeviceTyp(adapter, target_id, lun)
  514. int adapter;
  515. int target_id;
  516. int lun;
  517. {
  518.   struct _srbgettyp *srb;
  519.   int i;
  520.  
  521.   /* allocate a SCSI Request Block (SRB) */
  522.  
  523.   if ( (srb=calloc(sizeof( struct _srbgettyp), 1)) == 0 ) return(E$NoMem);
  524.  
  525.   srb->h.cmd = 1;
  526.   srb->h.adapter = adapter;
  527.   srb->target_id = target_id;
  528.   srb->lun = lun;
  529.  
  530.   /* Issue the request */
  531.   if ( (i=aspireq(srb)) ) {
  532.     switch ( srb->h.status )  {
  533.     case 0x82:
  534.       i = E$NoDevice;
  535.       break;
  536.     case 0x80:
  537.       i = E$AspiInval;
  538.       break;
  539.     case 0x81:
  540.       i = E$NoAdapter;
  541.       break;
  542.     case 0x02:
  543.       i = E$Abort;
  544.       break;
  545.     }
  546.   } else i = srb->typ;
  547.  
  548.   ( void ) free(srb);
  549.   return(i);
  550. }
  551.  
  552.  
  553. /*
  554.  * The ScsiIoError function is used to generate an unique errorcode
  555.  * from the three different errorcode sources.
  556.  * The errorcode sources are:
  557.  *   - The exit status of the aspi request
  558.  *   - The host adapter status
  559.  *   - The scsi target status
  560.  *   - The sense data structure
  561.  *
  562.  * Ahhmm ..... actually this makes FOUR different sources not three :-)
  563.  * The function is local to this module and called by all the SCSI-IO
  564.  * functions upon exit.
  565.  */
  566.  
  567. static int ScsiIoError(aspi_status, adapter_status, target_status, sense)
  568. int aspi_status;
  569. int adapter_status;
  570. int target_status;
  571. unsigned char *sense;
  572. {
  573.   int i;
  574.  
  575.   switch ( aspi_status )  {   /* check the aspi status */
  576.   case 0x82:
  577.     i = E$NoDevice;
  578.     break;
  579.   case 0x80:
  580.     i = E$AspiInval;
  581.     break;
  582.   case 0x81:
  583.     i = E$NoAdapter;
  584.     break;
  585.   case 0x02:
  586.     i = E$Abort;
  587.     break;
  588.   case 0x04:
  589.     /*
  590.      * Ok, this means scsi-io-error, so we see if
  591.      * we can find more details about the error.
  592.      */
  593.     i = E$IOErr;
  594.     if ( adapter_status )  {
  595.       switch ( adapter_status )  {
  596.       case 0x11:
  597.     i = E$SelTimeout;
  598.     break;
  599.       case 0x12:
  600.     i = E$DataOverrun;
  601.     break;
  602.       case 0x13:
  603.     i = E$BusFree;
  604.     break;
  605.       case 0x14:
  606.     i = E$BusFail;
  607.     break;
  608.       }
  609.     } else switch ( target_status )  {
  610.         /*
  611.          * If the adapter didn't show any errors
  612.          * we going to check the target to see if
  613.          * the target was the source of the error.
  614.          */
  615.     case 0x08:                         
  616.       i = E$TargetBusy;
  617.       break;
  618.     case 0x18:
  619.       i = E$Reservation;
  620.       break;
  621.     case 0x02:
  622.         /* 
  623.          * Allright, the target has send
  624.          * sense data to the sense-data allocation
  625.          * area at the end of the srb.
  626.      */
  627.       if ( sense != ( unsigned char *) 0 ) switch ( sense[2] & 0x0f )  {
  628.       case 0x00:  /* This means "no sense", but we check for End of Medium */
  629.         if ( sense[2] & 0x40 ) i = E$EndOfMedium;
  630.         break;
  631.       case 0x01:
  632.         i = E$NoErr;/* this would be pretty stupid to report, but anyway */
  633.     break;
  634.       case 0x02:
  635.     i = E$NotReady;
  636.     break;
  637.       case 0x03:
  638.     i = E$Medium;
  639.     break;
  640.       case 0x04:
  641.     i = E$Hardware;
  642.     break;
  643.       case 0x05:
  644.     i = E$IllegalReq;
  645.     break;
  646.       case 0x06:
  647.         i = E$UnitAttention;
  648.     break;
  649.       case 0x07:
  650.         i = E$DataProtect;
  651.     break;
  652.       case 0x08:
  653.     i = E$BlankCheck;
  654.     break;
  655.       case 0x0b:
  656.     i = E$TargetAbort;
  657.     break;
  658.       case 0x0d:
  659.     i = E$VolOverflow;
  660.     break;
  661.       }
  662.       break;
  663.     }
  664.     break;
  665.   }
  666.   return(i);
  667. }
  668.  
  669. int SCSIInquiry(adapter, target_id, lun, inq, sense)
  670. int adapter;
  671. int target_id;
  672. int lun;
  673. scsiinquiry far *inq;
  674. unsigned char *sense;
  675. {
  676.   struct _srbio *srb;
  677.   int i,j;
  678.  
  679.   /* allocate a SCSI Request Block (SRB) */
  680.   if ( (srb=calloc(sizeof(struct _srbio), 1)) == 0 ) return(E$NoMem);
  681.  
  682.   srb->h.cmd = 2;
  683.   srb->h.adapter = adapter;
  684.   srb->h.flags = (1<<3);
  685.   srb->target_id = target_id;
  686.   srb->lun = lun;
  687.   srb->buf_seg = FP_SEG(inq);
  688.   srb->buf_off = FP_OFF(inq);
  689.   srb->alloc_len = sizeof( scsiinquiry );
  690.   srb->sense_len = 14;
  691.   srb->cdb_len = 6;
  692.   srb->ccb.inq.cmd = 0x12;
  693.   srb->ccb.inq.lun = lun;
  694.   srb->ccb.inq.len = sizeof( scsiinquiry );
  695.  
  696.   if ( (i=aspireq(srb)) ) {
  697.     i = ScsiIoError(srb->h.status, srb->adapter_status,
  698.                     srb->target_status, srb->ccb.inq.sense);
  699.   }
  700.  
  701.   if ( sense ) for(j=0; j<14; ++j) sense[j] = srb->ccb.inq.sense[j];
  702.  
  703.   ( void ) free(srb);
  704.   return(i);
  705. }
  706.  
  707.  
  708. int SCSIResetDevice(adapter, target_id, lun)
  709. int adapter;
  710. int target_id;
  711. int lun;
  712. {
  713.   struct _srbreset *srb;
  714.   int i;
  715.  
  716.  
  717.   /* allocate a SCSI Request Block (SRB) */
  718.  
  719.   if ( (srb=calloc(sizeof(struct _srbreset), 1)) == 0 ) return(E$NoMem);
  720.  
  721.   srb->h.cmd = 4;
  722.   srb->h.adapter = 0;
  723.   srb->target_id = target_id;
  724.   srb->lun = lun;
  725.  
  726.   if ( (i=aspireq(srb)) )
  727.     i = ScsiIoError(srb->h.status, srb->adapter_status,
  728.             srb->target_status, ( unsigned char far * ) 0);
  729.  
  730.   ( void ) free (srb);
  731.   return(i);
  732. }
  733.  
  734. /*
  735.  * The following commands are "Sequencial-Access Device" specific.
  736.  */
  737.  
  738. int SCSIErase(adapter, target_id, lun, immediate, lng, sense)
  739. int adapter;
  740. int target_id;
  741. int lun;
  742. int immediate;
  743. int lng;
  744. unsigned char *sense;
  745. {
  746.   struct _srbio *srb;
  747.   int i;
  748.  
  749.   /* allocate a SCSI Request Block (SRB) */
  750.   if ( (srb=calloc(sizeof(struct _srbio), 1)) == 0 ) return(E$NoMem);
  751.  
  752.   srb->h.cmd = 2;
  753.   srb->h.adapter = adapter;
  754.   srb->target_id = target_id;
  755.   srb->lun = lun;
  756.   srb->sense_len = 14;
  757.   srb->cdb_len = 6;
  758.   srb->ccb.c6.cmd = 0x19;
  759.   srb->ccb.c6.flag0 = lng;
  760.   srb->ccb.c6.flag1 = immediate;
  761.   srb->ccb.c6.lun = lun;
  762.  
  763.   if ( (i=aspireq(srb)) ) {
  764.     if ( sense ) for(i=0; i<14; ++i) sense[i] = srb->ccb.c6.sense[i];
  765.     i = ScsiIoError(srb->h.status, srb->adapter_status,
  766.                     srb->target_status, srb->ccb.c6.sense);
  767.   }
  768.  
  769.   ( void ) free(srb);
  770.  
  771.   return(i);
  772. }
  773.  
  774.  
  775. int SCSILoad(adapter, target_id, lun, immediate, load, retention, eot, sense)
  776. int adapter;
  777. int target_id;
  778. int lun;
  779. int immediate;
  780. int load;
  781. int retention;
  782. int eot;
  783. unsigned char *sense;
  784. {
  785.   struct _srbio *srb;
  786.   int i;
  787.  
  788.  
  789.   /* allocate a SCSI Request Block (SRB) */
  790.   if ( (srb=calloc(sizeof(struct _srbio), 1)) == 0 ) return(E$NoMem);
  791.  
  792.   srb->h.cmd = 2;
  793.   srb->h.adapter = adapter;
  794.   srb->target_id = target_id;
  795.   srb->lun = lun;
  796.   srb->sense_len = 14;
  797.   srb->cdb_len = 6;
  798.   srb->ccb.ld.cmd = 0x1b;
  799.   srb->ccb.ld.immediate = immediate;
  800.   srb->ccb.ld.lun = lun;
  801.   srb->ccb.ld.load = load;
  802.   srb->ccb.ld.retention = retention;
  803.   srb->ccb.ld.eot = eot;
  804.  
  805.   if ( (i=aspireq(srb)) )  {
  806.     if ( sense ) for(i=0; i<14; ++i) sense[i] = srb->ccb.ld.sense[i];
  807.     i = ScsiIoError(srb->h.status, srb->adapter_status,
  808.                     srb->target_status, srb->ccb.ld.sense);
  809.   }
  810.  
  811.   ( void ) free(srb);
  812.  
  813.   return(i);
  814. }
  815.  
  816.  
  817. int SCSIRead(adapter, target_id, lun, buf, len, l2bf, sili, fixed, sense)
  818. int adapter;
  819. int target_id;
  820. int lun;
  821. char far *buf;
  822. DWORD len;
  823. int l2bf;
  824. int sili;
  825. int fixed;
  826. unsigned char *sense;
  827. {
  828.   DWORD length;
  829.   struct _srbio *srb;
  830.   int i;
  831.  
  832.   /* allocate a SCSI Request Block (SRB) in the lower 1 MB */
  833.  
  834.   if ( (srb=calloc((DWORD) sizeof(struct _srbio), 1)) == 0 ) return(E$NoMem);
  835.  
  836.   length = ( fixed ) ? len>>l2bf : len;
  837.  
  838.   srb->h.cmd = 2;           /* scsi I/O request */
  839.   srb->h.adapter = adapter;
  840.   srb->h.flags = (1<<3);
  841.   srb->target_id = target_id;
  842.   srb->lun = lun;
  843.   srb->alloc_len = len;
  844.   srb->sense_len = 14;
  845.   srb->buf_seg = FP_SEG(buf);
  846.   srb->buf_off = FP_OFF(buf);
  847.   srb->cdb_len = 6;
  848.   srb->ccb.rdwr.cmd = 0x08;
  849.   srb->ccb.rdwr.fixed = fixed;
  850.   srb->ccb.rdwr.sili = sili;
  851.   srb->ccb.rdwr.lun = lun;
  852.   srb->ccb.rdwr.len_0 = (length & 0xff);
  853.   srb->ccb.rdwr.len_1 = ((length>>8) & 0xff);
  854.   srb->ccb.rdwr.len_2 = ((length>>16) & 0xff);
  855.  
  856.   if ( (i=aspireq(srb)) )  {
  857.     if ( sense ) for(i=0; i<14; ++i) sense[i] = srb->ccb.rdwr.sense[i];
  858.     i = ScsiIoError(srb->h.status, srb->adapter_status,
  859.                     srb->target_status, srb->ccb.rdwr.sense);
  860.   }
  861.  
  862.   ( void ) free(srb);
  863.   return(i);
  864. }
  865.  
  866.  
  867. int SCSIReadBlockLimits(adapter, target_id, lun, lim, sense)
  868. int adapter;
  869. int target_id;
  870. int lun;
  871. blocklimit *lim;
  872. unsigned char *sense;
  873. {
  874.   struct _srbio *srb;
  875.   char *buf;
  876.   unsigned char far *block;
  877.   int i, j;
  878.  
  879.   /* allocate a SCSI Request Block (SRB) */
  880.   if ( (srb=calloc(sizeof(struct _srbio), 1)) == 0 ) return(E$NoMem);
  881.  
  882.   /* allocate small data buffer */
  883.   if ( (buf=calloc(64, 1)) ==  0 ) return(E$NoMem);
  884.  
  885.   block = ( unsigned char far * ) buf;
  886.  
  887.   srb->h.cmd = 2;
  888.   srb->h.adapter = adapter;
  889.   srb->h.flags = (1<<3);
  890.   srb->target_id = target_id;
  891.   srb->lun = lun;
  892.   srb->alloc_len = 6;
  893.   srb->sense_len = 14;
  894.   srb->buf_seg = FP_SEG(block);
  895.   srb->buf_off = FP_OFF(block);
  896.   srb->cdb_len = 6;
  897.   srb->ccb.c6.cmd = 0x05;
  898.   srb->ccb.c6.lun = lun;
  899.  
  900.   if ( (i=aspireq(srb)) )  {
  901.     if ( sense ) for(i=0; i<14; ++i) sense[i] = srb->ccb.c6.sense[i];
  902.     i = ScsiIoError(srb->h.status, srb->adapter_status,
  903.                     srb->target_status, srb->ccb.c6.sense);
  904.   } else  {
  905.     lim->max =   (    ((( DWORD ) buf[1])<<16) |
  906.                       ((( DWORD ) buf[2])<<8)  |
  907.                       ((( DWORD ) buf[3])) );
  908.     lim->min =   (    ((( DWORD ) buf[4])<<8) |
  909.                       ((( DWORD ) buf[5])) );
  910.   }
  911.  
  912.   ( void ) free(buf);
  913.   ( void ) free(srb);
  914.  
  915.   return(i);
  916. }
  917.  
  918. int SCSIRewind(adapter, target_id, lun, immediate, sense)
  919. int adapter;
  920. int target_id;
  921. int lun;
  922. int immediate;
  923. unsigned char *sense;
  924. {
  925.   struct _srbio *srb;
  926.   int i;
  927.  
  928.   /* allocate a SCSI Request Block (SRB) */
  929.   if ( (srb=calloc(sizeof(struct _srbio), 1)) == 0 ) return(E$NoMem);
  930.  
  931.   srb->h.cmd = 2;
  932.   srb->h.adapter = adapter;
  933.   srb->target_id = target_id;
  934.   srb->lun = lun;
  935.   srb->sense_len = 14;
  936.   srb->cdb_len = 6;
  937.   srb->ccb.c6.cmd = 0x01;
  938.   srb->ccb.c6.lun = lun;
  939.   srb->ccb.c6.flag0 = immediate;
  940.  
  941.   if ( (i=aspireq(srb)) )  {
  942.     if ( sense ) for(i=0; i<14; ++i) sense[i] = srb->ccb.c6.sense[i];
  943.     i = ScsiIoError(srb->h.status, srb->adapter_status,
  944.                     srb->target_status, srb->ccb.c6.sense);
  945.   }
  946.  
  947.   ( void ) free(srb);
  948.  
  949.   return(i);
  950. }
  951.  
  952.  
  953. int SCSISpace(adapter, target_id, lun, code, count, sense)
  954. int adapter;
  955. int target_id;
  956. int lun;
  957. int code;
  958. long count;
  959. unsigned char *sense;
  960. {
  961.   DWORD lcount;
  962.   struct _srbio *srb;
  963.   int i;
  964.  
  965.   /* allocate a SCSI Request Block (SRB) */
  966.   if ( (srb=calloc(sizeof(struct _srbio), 1)) == 0 ) return(E$NoMem);
  967.  
  968.   lcount = count;
  969.  
  970.   srb->h.cmd = 2;
  971.   srb->h.adapter = adapter;
  972.   srb->target_id = target_id;
  973.   srb->lun = lun;
  974.   srb->sense_len = 14;
  975.   srb->cdb_len = 6;
  976.   srb->ccb.spc.cmd = 0x11;
  977.   srb->ccb.spc.code = code;
  978.   srb->ccb.spc.lun = lun;
  979.   srb->ccb.spc.cnt0 = (lcount & 0xff);
  980.   srb->ccb.spc.cnt1 = ((lcount>>8) & 0xff);
  981.   srb->ccb.spc.cnt2 = ((lcount>>16) & 0xff);
  982.  
  983.   if ( (i=aspireq(srb)) )  {
  984.     if ( sense ) for(i=0; i<14; ++i) sense[i] = srb->ccb.spc.sense[i];
  985.     i = ScsiIoError(srb->h.status, srb->adapter_status,
  986.                     srb->target_status, srb->ccb.spc.sense);
  987.   }
  988.  
  989.   ( void ) free(srb);
  990.  
  991.   return(i);
  992. }
  993.  
  994.  
  995. int SCSIWrite(adapter, target_id, lun, buf, len, l2bf, fixed, sense)
  996. int adapter;
  997. int target_id;
  998. int lun;
  999. char far *buf;
  1000. DWORD len;
  1001. int l2bf;
  1002. int fixed;
  1003. unsigned char *sense;
  1004. {
  1005.   DWORD length;
  1006.   struct _srbio *srb;
  1007.   int i;
  1008.  
  1009.   /* allocate a SCSI Request Block (SRB) in the lower 1 MB */
  1010.  
  1011.   if ( (srb=calloc(sizeof(struct _srbio), 1)) == 0 ) return(E$NoMem);
  1012.  
  1013.   length = ( fixed ) ? len>>l2bf : len;
  1014.  
  1015.   srb->h.cmd = 2;           /* scsi I/O request */
  1016.   srb->h.adapter = adapter;
  1017.   srb->h.flags = (1<<4);
  1018.   srb->target_id = target_id;
  1019.   srb->lun = lun;
  1020.   srb->alloc_len = len;
  1021.   srb->sense_len = 14;
  1022.   srb->buf_seg = FP_SEG(buf);
  1023.   srb->buf_off = FP_OFF(buf);
  1024.   srb->cdb_len = 6;
  1025.   srb->ccb.rdwr.cmd = 0x0a;
  1026.   srb->ccb.rdwr.fixed = fixed;
  1027.   srb->ccb.rdwr.lun = lun;
  1028.   srb->ccb.rdwr.len_0 = (length & 0xff);
  1029.   srb->ccb.rdwr.len_1 = ((length>>8) & 0xff);
  1030.   srb->ccb.rdwr.len_2 = ((length>>16) & 0xff);
  1031.  
  1032.   if ( (i=aspireq(srb)) )  {
  1033.     if ( sense ) for(i=0; i<14; ++i) sense[i] = srb->ccb.rdwr.sense[i];
  1034.     i = ScsiIoError(srb->h.status, srb->adapter_status,
  1035.                     srb->target_status, srb->ccb.rdwr.sense);
  1036.   }
  1037.  
  1038.   ( void ) free(srb);
  1039.   return(i);
  1040. }
  1041.  
  1042.  
  1043.  
  1044. int SCSIWriteFilemarks(adapter, target_id, lun, len, setmark, immediate, sense)
  1045. int adapter;
  1046. int target_id;
  1047. int lun;
  1048. DWORD len;
  1049. int setmark;
  1050. int immediate;
  1051. unsigned char *sense;
  1052. {
  1053.   DWORD length;
  1054.   struct _srbio *srb;
  1055.   int i;
  1056.  
  1057.   /* allocate a SCSI Request Block (SRB) */
  1058.  
  1059.   if ( (srb=calloc(sizeof(struct _srbio), 1)) == 0 ) return(E$NoMem);
  1060.  
  1061.   length = len;
  1062.  
  1063.   srb->h.cmd = 2;           /* scsi I/O request */
  1064.   srb->h.adapter = adapter;
  1065.   srb->target_id = target_id;
  1066.   srb->lun = lun;
  1067.   srb->sense_len = 14;
  1068.   srb->cdb_len = 6;
  1069.   srb->ccb.rdwr.cmd = 0x10;
  1070.   srb->ccb.rdwr.fixed = immediate;
  1071.   srb->ccb.rdwr.sili = setmark;
  1072.   srb->ccb.rdwr.lun = lun;
  1073.   srb->ccb.rdwr.len_0 = (length & 0xff);
  1074.   srb->ccb.rdwr.len_1 = ((length>>8) & 0xff);
  1075.   srb->ccb.rdwr.len_2 = ((length>>16) & 0xff);
  1076.  
  1077.   if ( (i=aspireq(srb)) )  {
  1078.     if ( sense ) for(i=0; i<14; ++i) sense[i] = srb->ccb.rdwr.sense[i];
  1079.     i = ScsiIoError(srb->h.status, srb->adapter_status,
  1080.                     srb->target_status, srb->ccb.rdwr.sense);
  1081.   }
  1082.  
  1083.   ( void ) free(srb);
  1084.   return(i);
  1085. }
  1086.  
  1087. #ifdef TEST_ASPI
  1088. main()
  1089. {
  1090.   aspiinquiry inq;
  1091.   scsiinquiry sinq;
  1092.   int i, j;
  1093.   long l;
  1094.   char *buf;
  1095.  
  1096.   aspiinit();
  1097.  
  1098.   inq.adapter_num = 0;
  1099.   HostAdapterInquiry(&inq);
  1100.  
  1101.  
  1102.   printf("%d adapters, target:%d\n", inq.adapters, inq.target_id);
  1103.   printf("Manager id: %s\n", inq.manager_id);
  1104.   printf("adapter id: %s\n", inq.adapter_id);
  1105.  
  1106.   printf("\nrecsize: %ld, log2(recsize)= %d\n", recsize, logrec);
  1107.  
  1108.   if ( (i=SCSIInquiry(TARGET, &sinq, 0)) != E$NoErr )  {
  1109.     printf("Scsi Inquiry returned %d\n", i);
  1110.   } else  {
  1111.     printf("type,pqual,dqual: %d, %d, %d\n", sinq.per_type,
  1112.             sinq.per_qualify, sinq.dev_qualify);
  1113.     printf("vendor_id:%.8s\n", sinq.vendor_id);
  1114.     printf("product_id:%.16s\n", sinq.product_id);
  1115.     printf("revision:%.4s\n", sinq.revision);
  1116.     printf("vendor:%.20s\n", sinq.vendor);
  1117.   }
  1118.  
  1119.   if ( (buf=malloc(32768)) == 0 ) {
  1120.     printf("can't alloc buf\n");
  1121.     exit(0);
  1122.   }
  1123.  
  1124.   printf("\nBlocklimits, max:%ld min:%ld\n", lim.max, lim.min);
  1125.  
  1126.   i = SCSILoad(TARGET, 0, 1, 0, 0, 0);
  1127.   printf("\nLoad returned %d\n -->", i);
  1128.  
  1129. #if 0
  1130.   printf("seeking to tape file 2...\n");
  1131.  
  1132.   if ( (i=SCSISpace(TARGET, 1, ( DWORD ) 1, 0)) )
  1133.     printf("Error %d\n", i );
  1134.   else printf("OK\n");
  1135.  
  1136.   printf("seeking to tape block 400 on file 2...\n");
  1137.   if ( (i=SCSISpace(TARGET, 0, ( DWORD ) 400, 0)) )
  1138.     printf("Error %d\n", i );
  1139.   else printf("OK\n");
  1140.  
  1141.   printf("Writing two sectors..(this should return an error)...\n");
  1142.   i = SCSIWrite(TARGET, buf, 1024l, 9, 1, 0);
  1143.   printf("Write returned %d\n", i);
  1144.  
  1145.   printf("seeking back two sectors...\n");
  1146.   if ( (i=SCSISpace(TARGET, 0, -2l, 0)) )
  1147.     printf("Error %d\n", i );
  1148.   else printf("OK\n");
  1149.  
  1150.   printf("reading back the two sectors...\n");
  1151.   i = SCSIRead(TARGET, buf, 1024l, 9, 0, 1, 0);
  1152.   printf("Read returned %d\n", i);
  1153.  
  1154.   printf("rewinding the tape...\n");
  1155.   i = SCSIRewind(TARGET, 0, 0);
  1156.   printf("Rewind returned %d\n", i);
  1157.  
  1158.   printf("seeking to the end of the data...\n");
  1159.   if ( (i=SCSISpace(TARGET, 3, 0l, 0)) )
  1160.     printf("Error %d\n", i );
  1161.   else printf("OK\n");
  1162.  
  1163.   printf("Writing two sectors...\n");
  1164.   i = SCSIWrite(TARGET, buf, 1024l, 9, 1, 0);
  1165.   printf("Write returned %d\n", i);
  1166.  
  1167.   printf("Writing two sectors...\n");
  1168.   i = SCSIWrite(TARGET, buf, 1024l, 9, 1, 0);
  1169.   printf("Write returned %d\n", i);
  1170.  
  1171.   printf("Writing a file mark !\n");
  1172.   i = SCSIWriteFilemarks(TARGET, 1l, 0, 0, 0);
  1173.   printf("Write returned %d\n", i);
  1174.  
  1175.   printf("rewinding the tape...\n");
  1176.   i = SCSIRewind(TARGET, 0, 0);
  1177.   printf("Rewind returned %d\n", i);
  1178.  
  1179.   printf("Now counting files ...\n");
  1180.   i = 0;
  1181.   while ( !SCSISpace(TARGET, 1, 1l, 0) ) ++ i;
  1182.   printf("... there are %d files on the tape now\n",i);
  1183.  
  1184.   printf("rewinding the tape...\n");
  1185.   i = SCSIRewind(TARGET, 0, 0);
  1186.   printf("Rewind returned %d\n", i);
  1187.  
  1188.   printf("eraseing the tape...\n");
  1189.   i = SCSIErase(TARGET, 0, 0, 0);
  1190.   printf("erase returned %d\n", i);
  1191. #endif
  1192.  
  1193.   l = 0l;
  1194.  
  1195.   printf("Now see what kind of errors we get at Overflow\n");
  1196.   while ( l < 4080l ) {
  1197.     i = SCSIRead(TARGET, buf, 32768l, 9, 0, 1, rsense);
  1198.     if ( i ) {
  1199.       printf("reading block # %ld: errno: %d rsense:", l, i);
  1200.       for(j=0; j<14; ++j) printf(" %02x", rsense[j]);
  1201.       printf("\n");
  1202.     }
  1203.     ++l;
  1204.   }
  1205.  
  1206. /*
  1207.   while ( !(i=SCSIWrite(TARGET, buf, 32768l, 9, 1, rsense)) )  ++l;
  1208.   printf("last block was %ld\n", l);
  1209.   printf("errno: %d sense:", i);
  1210.   for(j=0; j<14; ++j) printf(" %02x", rsense[j]);
  1211.   printf("\n");
  1212. */
  1213.  
  1214.   i = SCSILoad(TARGET, 0, 0, 0, 0, 0);
  1215.   printf("Unload returned %d\n -->", i);
  1216.   free(buf);
  1217. }
  1218. #endif
  1219.