home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 13 / MA_Cover_13.bin / source / c / stefanb_src / private_projects / yath / yath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-06  |  18.5 KB  |  681 lines

  1. /*
  2.  * yath.c   V0.06 (beta)
  3.  *
  4.  * main tape handler routine
  5.  *
  6.  * (c) 1991/2 by Stefan Becker
  7.  *
  8.  */
  9.  
  10. #include "yath.h"
  11.  
  12. struct Library *SysBase,*DOSBase;
  13. struct IOStdReq *ior;
  14. struct SCSICmd *scmd;
  15. UBYTE *command,*sense;
  16. #ifdef DEBUG
  17. struct MsgPort *MonitorPort;
  18. struct MsgPort *MReplyPort;
  19. struct MonitorMessage *MonitorMsg;
  20. #endif
  21.  
  22. /* Handler main entry point */
  23. __geta4 void HandlerEntry(void)
  24. {
  25.  struct MsgPort *mp;                     /* Handler process ID */
  26.  struct DosList *dn;                     /* Handler device node */
  27.  struct DosPacket *dp;                   /* Pointer to last received packet */
  28.  struct DosList *vn;                     /* Handler volume node */
  29.  ULONG vnbptr;                           /* BPTR to handler volume node */
  30.  struct FileSysStartupMsg *fssm;         /* Filehandler startup parameters */
  31.  struct SCSIStuff *ss;                   /* Memory for SCSI stuff */
  32.  struct MsgPort *iop;                    /* Message Port for IO requests */
  33.  ULONG BytesPB,BufSize,BufType;          /* Size parameters */
  34.  ULONG NumBlocks,BufBlocks,BlocksUsed=0; /* Block parameters */
  35.  BOOL notend=TRUE;                       /* State flags - not ended yet   */
  36.  BOOL open=FALSE;                        /*             - stream opened   */
  37.  BOOL read;                              /*             - read from tape  */
  38.  BOOL inhibit=FALSE;                     /*             - handler blocked */
  39.  UBYTE *Buffer[2],*BufP;                 /* Buffer pointers */
  40.  ULONG BufNum,BufB;                      /* Buffer counters */
  41.  BOOL BufDirty;                          /* Buffer dirty flag */
  42.  
  43.  /* Initialize ExecBase library pointer */
  44.  SysBase=*((struct Library **) 4);
  45.  
  46.  /* Open dos.library V36 or better */
  47.  if (!(DOSBase=OpenLibrary(DOSNAME,36))) return;
  48.  
  49.  /* Get process parameters */
  50.  mp=&((struct Process *) FindTask(NULL))->pr_MsgPort;
  51.  
  52.  /* Get handler startup packet */
  53.  WaitPort(mp);
  54.  dp=(struct DosPacket *) GetMsg(mp)->mn_Node.ln_Name;
  55.  
  56.  /* Got a startup message? */
  57.  if (!(fssm=(struct FileSysStartupMsg *) BADDR(dp->dp_Arg2))) goto e1;
  58.  
  59.  /* Allocate memory for SCSI stuff */
  60.  if (!(ss=AllocMem(sizeof(struct SCSIStuff),MEMF_PUBLIC|MEMF_CLEAR))) goto e1;
  61.  
  62.  /* Open device */
  63.  if (!(iop=CreateMsgPort())) goto e2;
  64.  if (!(ior=CreateIORequest(iop,sizeof(struct IOStdReq)))) goto e3;
  65.  if (OpenDevice((char *) BADDR(fssm->fssm_Device)+1,fssm->fssm_Unit,
  66.                 (struct IORequest *) ior,fssm->fssm_Flags))
  67.   goto e4;
  68.  
  69.  /* Set up SCSI stuff */
  70.  scmd=&ss->scmd;
  71.  command=ss->command;
  72.  sense=ss->sense;
  73.  ior->io_Command=HD_SCSICMD;
  74.  ior->io_Data=(APTR) scmd;
  75.  ior->io_Length=sizeof(struct SCSICmd);
  76.  ss->scmd.scsi_Command=command;
  77.  ss->scmd.scsi_CmdLength=6;
  78.  ss->scmd.scsi_CmdActual=6;
  79.  ss->scmd.scsi_SenseData=sense;
  80.  ss->scmd.scsi_SenseLength=SENSELEN;
  81.  
  82.  /* Calculate size parameters */
  83.  {
  84.   ULONG *env=BADDR(fssm->fssm_Environ);
  85.  
  86.   BytesPB=4*env[DE_SIZEBLOCK];
  87.   BufBlocks=env[DE_NUMBUFFERS];
  88.   BufSize=BytesPB*BufBlocks;
  89.   BufType=env[DE_BUFMEMTYPE];
  90.   NumBlocks=env[DE_NUMHEADS]*env[DE_BLKSPERTRACK]*
  91.             (env[DE_UPPERCYL]-env[DE_LOWCYL]+1);
  92.  }
  93.  
  94.  /* Set up device node */
  95.  dn=(struct DosList *) BADDR(dp->dp_Arg3);
  96.  dn->dol_Task=mp;
  97.  
  98.  /* Set up volume node */
  99.  if (vn=MakeDosEntry("Streamer Tape",DLT_VOLUME))
  100.   {
  101.    vn->dol_Task=mp;
  102.    DateStamp(&vn->dol_misc.dol_volume.dol_VolumeDate);
  103.    vn->dol_misc.dol_volume.dol_DiskType=ID_DOS_DISK;
  104.    if (!AddDosEntry(vn))
  105.     {
  106.      FreeDosEntry(vn);
  107.      vn=NULL;
  108.     }
  109.   }
  110.  vnbptr=MKBADDR(vn);
  111.  
  112.  /* Got all resources, reply startup packet */
  113.  ReplyPkt(dp,DOSTRUE,dp->dp_Res2);
  114.  
  115. #ifdef DEBUG
  116.  MonitorPort=NULL; /* default: No debug monitor */
  117. #endif
  118.  
  119.  /* Handler main event loop */
  120.  while (notend)
  121.   {
  122.    struct Message *msg;
  123.  
  124.    /* Wait for next packet */
  125.    WaitPort(mp);
  126.  
  127.    /* Retrieve & process all packets */
  128.    while (msg=GetMsg(mp))
  129.     {
  130.      dp=(struct DosPacket *) msg->mn_Node.ln_Name;
  131.  
  132.      switch(dp->dp_Type)
  133.       {
  134.        case ACTION_FINDINPUT:  /* Open stream for reading an existing file */
  135.        case ACTION_FINDOUTPUT: /* Open stream for writing a new file */
  136.        case ACTION_FINDUPDATE: /* Open stream for writing to an existing file */
  137.         if (open || inhibit || !notend)
  138.          ReplyPkt(dp,DOSFALSE,ERROR_OBJECT_IN_USE);
  139.         else
  140.          {
  141.           BOOL openerr=TRUE;
  142.  
  143.           /* Allocate memory for buffers */
  144.           if (Buffer[0]=AllocMem(BufSize,BufType))
  145.            if (Buffer[1]=AllocMem(BufSize,BufType))
  146.             openerr=FALSE;
  147.            else
  148.             FreeMem(Buffer[0],BufSize);
  149.  
  150.           /* Got all needed memory? */
  151.           if (openerr)
  152.            ReplyPkt(dp,DOSFALSE,ERROR_NO_FREE_STORE);
  153.           else
  154.            {
  155.             /* Eat up first sense data */
  156.             DoSCSICmd(SCSI_SENSE,0,0,0);
  157.  
  158.             /* Special file name detection */
  159.             {
  160.              char *bstr=BADDR(dp->dp_Arg3);
  161.  
  162.              /* Valid BCPL string? */
  163.              if (bstr)
  164.               {
  165.                ULONG len=*bstr++; /* BCPL length byte */
  166.                char *cstr;
  167.  
  168.                /* Get memory for C string */
  169.                if (len && (cstr=AllocMem(len+1,MEMF_CLEAR)))
  170.                 {
  171.                  char *cp;
  172.  
  173.                  strncpy(cstr,bstr,len); /* Copy BCPL string */
  174.  
  175.                  /* Search end of device name, End of string reached? */
  176.                  if ((cp=strchr(cstr,':')) && (*++cp!='\0'))
  177.                   /* No, special file name detected */
  178.                   switch(*cp)
  179.                    {
  180.                     case '*': /* <dev>:*<n>  Skip <n> File Marks */
  181.                      LONG n=strtol(cp+1,&cp,10); /* Read number */
  182.  
  183.                      /* Valid value? Yes, issue SCSI Space command */
  184.                      if (n!=0) DoSCSICmd(SCSI_SPACE,n,0,0);
  185.                      break;
  186.  
  187.                     default:  /* Not recognized file name */
  188.                      break;
  189.                    }
  190.  
  191.                  FreeMem(cstr,len+1); /* Free memory */
  192.                 }
  193.               }
  194.             }
  195.  
  196.             /* Read from or write to tape? */
  197.             if (read=dp->dp_Type==ACTION_FINDINPUT)
  198.              {
  199.               /* Read from tape. Read first buffer */
  200.               if (openerr=DoSCSICmd(SCSI_READ,(ULONG) Buffer[0],BufSize,
  201.                                     BufBlocks))
  202.                {
  203.                 /* An error occured, close stream */
  204.                 FreeMem(Buffer[0],BufSize);
  205.                 FreeMem(Buffer[1],BufSize);
  206.                 ReplyPkt(dp,DOSFALSE,openerr);
  207.                 break;
  208.                }
  209.  
  210.               /* Set pointers & counters */
  211.               BufNum=1;
  212.               BufP=Buffer[1];
  213.               BufB=0;
  214.              }
  215.             else
  216.              {
  217.               /* Write to tape. Set pointers & counters */
  218.               BufNum=0;
  219.               BufP=Buffer[0];
  220.               BufB=BufSize;
  221.              }
  222.  
  223.             /* Stream opened */
  224. #ifdef DEBUG
  225.             /* Create debug message reply port */
  226.             if (MReplyPort=CreateMsgPort())
  227.              {
  228.               /* Create debug message */
  229.               if (MonitorMsg=AllocMem(sizeof(struct MonitorMessage),
  230.                                       MEMF_CLEAR|MEMF_PUBLIC))
  231.                {
  232.                 /* Initialize debug message */
  233.                 MonitorMsg->mm_msg.mn_ReplyPort=MReplyPort;
  234.                 MonitorMsg->mm_msg.mn_Length=sizeof(struct MonitorMessage);
  235.  
  236.                 /* Find debug monitor */
  237.                 Forbid();         /* Singletasking */
  238.                 if (MonitorPort=FindPort(MPORTNAME)) /* Search monitor port */
  239.                  MONITOR(YATH_OPEN,read,0);
  240.                 Permit();         /* Multitasking */
  241.  
  242.                 /* Debug monitor found? */
  243.                 if (!MonitorPort)
  244.                  {
  245.                   /* No, free resources */
  246.                   FreeMem(MonitorMsg,sizeof(MonitorMsg));
  247.                   DeleteMsgPort(MReplyPort);
  248.                  }
  249.                }
  250.               else DeleteMsgPort(MReplyPort);
  251.              }
  252. #endif
  253.             open=TRUE;
  254.             BufDirty=FALSE;
  255.             ReplyPkt(dp,DOSTRUE,dp->dp_Res2);
  256.            }
  257.          }
  258.         break;
  259.  
  260.        case ACTION_END: /* Close stream */
  261.         if (!open)
  262.          ReplyPkt(dp,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  263.         else
  264.          {
  265.           /* Flush Buffers */
  266.           if (BufDirty) DoSCSICmd(SCSI_WRITE,(ULONG) Buffer[BufNum],BufSize,
  267.                                   BufBlocks);
  268.  
  269.           /* Write file end mark to tape */
  270.           if (!read) DoSCSICmd(SCSI_WEOFM,0,0,0);
  271.  
  272.           /* Free buffer memory */
  273.           FreeMem(Buffer[0],BufSize);
  274.           FreeMem(Buffer[1],BufSize);
  275.  
  276.           /* Stream closed */
  277.           MONITOR(YATH_CLOSE,0,0);
  278. #ifdef DEBUG
  279.           if (MonitorPort)
  280.            {
  281.             FreeMem(MonitorMsg,sizeof(struct MonitorMessage));
  282.             DeleteMsgPort(MReplyPort);
  283.             MonitorPort=NULL;
  284.            }
  285. #endif
  286.           open=FALSE;
  287.           ReplyPkt(dp,DOSTRUE,dp->dp_Res2);
  288.          }
  289.         break;
  290.  
  291.        case ACTION_READ: /* Read from stream */
  292.         if (!open || !read)
  293.          ReplyPkt(dp,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  294.         else
  295.          {
  296.           UBYTE *dstp=(UBYTE *) dp->dp_Arg2; /* Destination pointer */
  297.           ULONG dstb=dp->dp_Arg3;            /* Number of bytes to read */
  298.           ULONG act=0;                       /* Number of bytes read */
  299.           LONG err=0;                        /* Error flag */
  300.  
  301.           MONITOR(YATH_READ,dstb,0);
  302.  
  303.           /* Read all bytes */
  304.           while (dstb)
  305.            /* Number of bytes to read < Number of bytes in buffer? */
  306.            if (dstb<BufB)
  307.             {
  308.              /* Yes, copy from buffer (not empty yet) */
  309.              memcpy(dstp,BufP,dstb);
  310.  
  311.              /* Correct pointers & counters */
  312.              act+=dstb;
  313.              BufP+=dstb;
  314.              BufB-=dstb;
  315.              dstb=0;
  316.             }
  317.            else
  318.             {
  319.              /* No, empty buffer and read from tape */
  320.              memcpy(dstp,BufP,BufB);
  321.  
  322.              /* Issue SCSI read command */
  323.              if (err=DoSCSICmd(SCSI_READ,(ULONG) Buffer[BufNum],BufSize,
  324.                                BufBlocks))
  325.               break;
  326.  
  327.              /* Correct pointers & counters */
  328.              BlocksUsed+=BufBlocks;
  329.              act+=BufB;
  330.              dstp+=BufB;
  331.              dstb-=BufB;
  332.  
  333.              /* Swtich to filled buffer */
  334.              BufNum^=1;
  335.              BufP=Buffer[BufNum];
  336.              BufB=BufSize;
  337.             }
  338.  
  339.           /* Did an error occur? */
  340.           if (err)
  341.            act=DOSTRUE;
  342.           else
  343.            err=dp->dp_Res2;
  344.  
  345.           ReplyPkt(dp,act,err);
  346.          }
  347.         break;
  348.  
  349.        case ACTION_WRITE: /* Write to stream */
  350.         if (!open || read)
  351.          ReplyPkt(dp,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  352.         else
  353.          {
  354.           UBYTE *srcp=(UBYTE *) dp->dp_Arg2; /* Source pointer */
  355.           ULONG srcb=dp->dp_Arg3;            /* Number of bytes to write */
  356.           ULONG act=0;                       /* Number of bytes written */
  357.           LONG err=0;                        /* Error flag */
  358.  
  359.           MONITOR(YATH_WRITE,srcb,0);
  360.  
  361.           /* Write all bytes */
  362.           while (srcb)
  363.            /* Number of bytes to write < Number of free bytes in buffer? */
  364.            if (srcb<BufB)
  365.             {
  366.              /* Yes, copy into buffer (not filled yet) */
  367.              memcpy(BufP,srcp,srcb);
  368.  
  369.              /* Correct pointers & counters */
  370.              act+=srcb;
  371.              BufP+=srcb;
  372.              BufB-=srcb;
  373.              srcb=0;
  374.  
  375.              /* We've written to the buffer, but not saved it yet */
  376.              BufDirty=TRUE;
  377.             }
  378.            else
  379.             {
  380.              /* No, fill buffer and write it to tape */
  381.              memcpy(BufP,srcp,BufB);
  382.  
  383.              /* Issue SCSI write command */
  384.              if (err=DoSCSICmd(SCSI_WRITE,(ULONG) Buffer[BufNum],BufSize,
  385.                                BufBlocks))
  386.               break;
  387.              BufDirty=FALSE; /* Buffer saved */
  388.  
  389.              /* Correct pointers & counters */
  390.              BlocksUsed+=BufBlocks;
  391.              act+=BufB;
  392.              srcp+=BufB;
  393.              srcb-=BufB;
  394.  
  395.              /* Switch to empty buffer */
  396.              BufNum^=1;
  397.              BufP=Buffer[BufNum];
  398.              BufB=BufSize;
  399.             }
  400.  
  401.           /* Did no error occur? */
  402.           if (!err) err=dp->dp_Res2;
  403.  
  404.           ReplyPkt(dp,act,err);
  405.          }
  406.         break;
  407.  
  408.        case ACTION_SEEK: /* Seek is not allowed on a tape! */
  409.         ReplyPkt(dp,(ULONG) -1,ERROR_ACTION_NOT_KNOWN);
  410.         break;
  411.  
  412.        case ACTION_CURRENT_VOLUME: /* Retrieve current volume */
  413.         if (notend)
  414.          ReplyPkt(dp,vnbptr,fssm->fssm_Unit);
  415.         else
  416.          ReplyPkt(dp,DOSFALSE,ERROR_OBJECT_IN_USE);
  417.         break;
  418.  
  419.        case ACTION_DISK_INFO: /* Retreive InfoData */
  420.         if (notend)
  421.          {
  422.           struct InfoData *id=BADDR(dp->dp_Arg1);
  423.  
  424.           id->id_NumSoftErrors=0;
  425.           id->id_UnitNumber=fssm->fssm_Unit;
  426.           id->id_DiskState=ID_VALIDATED;
  427.           id->id_NumBlocks=NumBlocks;
  428.           id->id_NumBlocksUsed=BlocksUsed;
  429.           id->id_BytesPerBlock=BytesPB;
  430.           id->id_DiskType=inhibit?ID_BUSY:ID_DOS_DISK;
  431.           id->id_VolumeNode=vnbptr;
  432.           id->id_InUse=open?DOSTRUE:DOSFALSE;
  433.  
  434.           ReplyPkt(dp,DOSTRUE,dp->dp_Res2);
  435.          }
  436.         else
  437.          ReplyPkt(dp,DOSFALSE,ERROR_OBJECT_IN_USE);
  438.         break;
  439.  
  440.        case ACTION_INHIBIT: /* Inhibit handler */
  441.         if (dp->dp_Arg1==DOSTRUE)
  442.          if (open || !notend)
  443.           {
  444.            ReplyPkt(dp,DOSFALSE,ERROR_OBJECT_IN_USE);
  445.            break;
  446.           }
  447.          else
  448.           {
  449.            /* Rewind tape */
  450.            DoSCSICmd(SCSI_SENSE,0,0,0);
  451.            DoSCSICmd(SCSI_REWND,0,0,0);
  452.  
  453.            /* Reset block counter */
  454.            BlocksUsed=0;
  455.  
  456.            inhibit=TRUE;
  457.           }
  458.         else
  459.          inhibit=FALSE;
  460.         ReplyPkt(dp,DOSTRUE,dp->dp_Res2);
  461.         break;
  462.  
  463.        case ACTION_FLUSH: /* Flush buffers, stop motor */
  464.         if (open)
  465.          {
  466.           MONITOR(YATH_FLUSH,0,0);
  467.  
  468.           /* Flush buffers */
  469.           if (BufDirty)
  470.            {
  471.             DoSCSICmd(SCSI_WRITE,(ULONG) Buffer[BufNum],BufSize,BufBlocks);
  472.             BufDirty=FALSE;
  473.            }
  474.  
  475.           ReplyPkt(dp,DOSTRUE,dp->dp_Res2);
  476.          }
  477.         else
  478.          ReplyPkt(dp,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  479.         break;
  480.  
  481.        case ACTION_DIE: /* Shut down handler */
  482.         if (open || inhibit)
  483.          ReplyPkt(dp,DOSFALSE,ERROR_OBJECT_IN_USE);
  484.         else
  485.          {
  486.           notend=FALSE;
  487.           /* Reply packet AFTER freeing all resources! */
  488.          }
  489.         break;
  490.  
  491.        default: /* Unknown ACTION --> error */
  492.         ReplyPkt(dp,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  493.         break;
  494.       }
  495.     }
  496.   }
  497.  
  498.  /* Clear process ID in device node */
  499.  dn->dol_Task=NULL;
  500.  
  501.  /* Remove volume node */
  502.  if (vn)
  503.   {
  504.    LockDosList(LDF_VOLUMES|LDF_WRITE);
  505.    RemDosEntry(vn);
  506.    UnLockDosList(LDF_VOLUMES|LDF_WRITE);
  507.    FreeDosEntry(vn);
  508.   }
  509.  
  510.  /* Wait until last I/O request is finished, then close device */
  511.  DoSCSICmd(SCSI_WAIT,0,0,0);
  512.  CloseDevice((struct IORequest *) ior);
  513.  
  514.  /* Free resources */
  515. e4: DeleteIORequest(ior);
  516. e3: DeleteMsgPort(iop);
  517. e2: FreeMem(ss,sizeof(struct SCSIStuff));
  518. e1: if (notend) /* Error or normal (ACTION_DIE) termination? */
  519.      ReplyPkt(dp,DOSFALSE,ERROR_NO_FREE_STORE); /* Error */
  520.     else /* normal termination */
  521.      {
  522.       Forbid(); /* Prevent UnLoadSeg() before exiting!! */
  523.       ReplyPkt(dp,DOSTRUE,dp->dp_Res2); /* reply ACTION_DIE packet */
  524.      }
  525.     CloseLibrary(DOSBase);
  526.     return;
  527. }
  528.  
  529. /* Version string. MUST be behind handler entry!! */
  530. const char ident[]=YATH_VERSION;
  531.  
  532. /* Issue a SCSI command */
  533. LONG DoSCSICmd(WORD action, ULONG parm1, ULONG parm2, ULONG parm3)
  534. {
  535.  static busy=FALSE;
  536.  
  537.  /* Is a SCSI command busy? */
  538.  if (busy)
  539.   {
  540.    /* Yes, wait until it finished */
  541.    WaitIO((struct IORequest *) ior);
  542.  
  543.    /* Not busy any more */
  544.    busy=FALSE;
  545.  
  546.    /* If an error occured, return */
  547.    if (ior->io_Error)
  548.     {
  549.      MONITOR(YATH_IOERR,ior->io_Error,scmd->scsi_Status);
  550.      return(ior->io_Error<<8+scmd->scsi_Status);
  551.     }
  552.   }
  553.  
  554.  /* SCSI_WAIT is a dummy command */
  555.  if (action==SCSI_WAIT) return(0);
  556.  
  557.  /* Initialize SCSI parameters */
  558.  switch(action)
  559.   {
  560.    case SCSI_READ:
  561.     command[0]=0x08;
  562.     command[1]=1;
  563.     command[2]=(parm3>>16)&0xff;
  564.     command[3]=(parm3>>8)&0xff;
  565.     command[4]=parm3&0xff;
  566.     scmd->scsi_Data=(UWORD *) parm1;
  567.     scmd->scsi_Length=parm2;
  568.     scmd->scsi_Flags=SCSIF_READ|SCSIF_AUTOSENSE;
  569.     busy=TRUE;
  570.     break;
  571.    case SCSI_WRITE:
  572.     command[0]=0x0A;
  573.     command[1]=1;
  574.     command[2]=(parm3>>16)&0xff;
  575.     command[3]=(parm3>>8)&0xff;
  576.     command[4]=parm3&0xff;
  577.     scmd->scsi_Data=(UWORD *) parm1;
  578.     scmd->scsi_Length=parm2;
  579.     scmd->scsi_Flags=SCSIF_WRITE|SCSIF_AUTOSENSE;
  580.     busy=TRUE;
  581.     break;
  582.    case SCSI_WEOFM:
  583.     command[0]=0x10;
  584.     command[1]=0;
  585.     command[2]=0;
  586.     command[3]=0;
  587.     command[4]=1;
  588.     scmd->scsi_Length=0;
  589.     scmd->scsi_Flags=SCSIF_AUTOSENSE;
  590.     break;
  591.    case SCSI_REWND:
  592.     command[0]=0x01;
  593.     command[1]=0;
  594.     command[2]=0;
  595.     command[3]=0;
  596.     command[4]=0;
  597.     scmd->scsi_Length=0;
  598.     scmd->scsi_Flags=SCSIF_AUTOSENSE;
  599.     busy=TRUE;
  600.     break;
  601.    case SCSI_SENSE:
  602.     command[0]=0x3;
  603.     command[1]=0;
  604.     command[2]=0;
  605.     command[3]=0;
  606.     command[4]=SENSELEN;
  607.     scmd->scsi_Data=sense;
  608.     scmd->scsi_Length=0;
  609.     scmd->scsi_Flags=SCSIF_READ|SCSIF_AUTOSENSE;
  610.     break;
  611.    case SCSI_SPACE:
  612.     command[0]=0x11;
  613.     command[1]=1;
  614.     command[2]=(parm1>>16)&0xff;
  615.     command[3]=(parm1>>8)&0xff;
  616.     command[4]=parm1&0xff;
  617.     scmd->scsi_Length=0;
  618.     scmd->scsi_Flags=SCSIF_AUTOSENSE;
  619.     busy=TRUE;
  620.     break;
  621.   }
  622.  
  623.  /* Initialize I/O request */
  624.  ior->io_Error=0;
  625.  MONITOR(YATH_SCSI,command[0],busy);
  626.  
  627.  /* What type of I/O operation? */
  628.  if (busy)
  629.   {
  630.    /* Asynchronous I/O */
  631.    ior->io_Flags=IOF_QUICK;
  632.    BeginIO((struct IORequest *) ior);
  633.  
  634.    /* I/O error? */
  635.    if (ior->io_Error)
  636.     {
  637.      busy=FALSE;
  638.      MONITOR(YATH_IOERR,ior->io_Error,scmd->scsi_Status);
  639.      return(ior->io_Error<<8+scmd->scsi_Status);
  640.     }
  641.  
  642.    /* Command already executed? */
  643.    if (ior->io_Flags&IOF_QUICK) busy=FALSE;
  644.   }
  645.  else
  646.   {
  647.    /* Synchronous I/O */
  648.    DoIO((struct IORequest *) ior);
  649.  
  650.    /* I/O error? */
  651.    if (ior->io_Error)
  652.     {
  653.      MONITOR(YATH_IOERR,ior->io_Error,scmd->scsi_Status);
  654.      return(ior->io_Error<<8+scmd->scsi_Status);
  655.     }
  656.   }
  657.  
  658.  /* No error */
  659.  return(0);
  660. }
  661.  
  662. #ifdef DEBUG
  663. /* Send a message to the debug monitor */
  664. void SendMonitor(ULONG cmd, ULONG arg1, ULONG arg2)
  665. {
  666.  /* Set message values */
  667.  MonitorMsg->mm_cmd=cmd;
  668.  MonitorMsg->mm_arg1=arg1;
  669.  MonitorMsg->mm_arg2=arg2;
  670.  
  671.  /* Send message to monitor */
  672.  PutMsg(MonitorPort,(struct Message *) MonitorMsg);
  673.  
  674.  /* Wait on reply */
  675.  WaitPort(MReplyPort);
  676.  
  677.  /* Retreive reply from port */
  678.  GetMsg(MReplyPort);
  679. }
  680. #endif
  681.