Logo Search packages:      
Sourcecode: cdrkit version File versions  Download package

scsi-os2.c

/*
 * This file has been modified for the cdrkit suite.
 *
 * The behaviour and appearence of the program code below can differ to a major
 * extent from the version distributed by the original author(s).
 *
 * For details, see Changelog file distributed with the cdrkit package. If you
 * received this file from another source then ask the distributing person for
 * a log of modifications.
 *
 */

/* @(#)scsi-os2.c 1.25 04/01/15 Copyright 1998 J. Schilling, C. Wohlgemuth */
/*
 *    Interface for the OS/2 ASPI-Router ASPIROUT.SYS ((c) D. Dorau).
 *          This additional driver is a prerequisite for using cdrecord.
 *          Get it from HOBBES or LEO.
 *
 *    Warning: you may change this source, but if you do that
 *    you need to change the _usal_version and _usal_auth* string below.
 *    You may not return "schily" for an SCG_AUTHOR request anymore.
 *    Choose your name instead of "schily" and make clear that the version
 *    string is related to a modified source.
 *
 *    XXX it currently uses static SRB and for this reason is not reentrant
 *
 *    Copyright (c) 1998 J. Schilling
 *    Copyright (c) 1998 C. Wohlgemuth for this interface.
 */
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; see the file COPYING.  If not, write to the Free Software
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#undef      sense

/*#define   DEBUG*/

/* For AspiRouter */
#include "usal/srb_os2.h"

/*
 *    Warning: you may change this source, but if you do that
 *    you need to change the _usal_version and _usal_auth* string below.
 *    You may not return "schily" for an SCG_AUTHOR request anymore.
 *    Choose your name instead of "schily" and make clear that the version
 *    string is related to a modified source.
 */
static      char  _usal_trans_version[] = "scsi-os2.c-1.25";      /* The version for this transport*/

#define     FILE_OPEN               0x0001
#define     OPEN_SHARE_DENYREADWRITE      0x0010
#define     OPEN_ACCESS_READWRITE         0x0002
#define     DC_SEM_SHARED                 0x01
#define     OBJ_TILE                0x0040
#define     PAG_READ                0x0001
#define     PAG_WRITE               0x0002
#define     PAG_COMMIT              0x0010

typedef unsigned long LHANDLE;
typedef unsigned long ULONG;
typedef unsigned char *PSZ;
typedef unsigned short USHORT;
typedef unsigned char UCHAR;

typedef LHANDLE   HFILE;
typedef ULONG     HEV;

#define     MAX_SCG           16    /* Max # of SCSI controllers */
#define     MAX_TGT           16
#define     MAX_LUN           8

struct usal_local {
      int   dummy;
};
#define     usallocal(p)      ((struct usal_local *)((p)->local))

#define     MAX_DMA_OS2 (63*1024) /* ASPI-Router allows up to 64k */

static      void  *buffer           = NULL;
static      HFILE driver_handle     = 0;
static      HEV   postSema    = 0;

static      BOOL  open_driver(SCSI *usalp);
static      BOOL  close_driver(void);
static      ULONG wait_post(ULONG ulTimeOut);
static      BOOL  init_buffer(void* mem);
static      void  exit_func(void);
static      void  set_error(SRB *srb, struct usal_cmd *sp);


static void
exit_func()
{
      if (!close_driver())
            fprintf(stderr, "Cannot close OS/2-ASPI-Router!\n");
}

/*
 * Return version information for the low level SCSI transport code.
 * This has been introduced to make it easier to trace down problems
 * in applications.
 */
static char *
usalo_version(SCSI *usalp, int what)
{
      if (usalp != (SCSI *)0) {
            switch (what) {

            case SCG_VERSION:
                  return (_usal_trans_version);
            /*
             * If you changed this source, you are not allowed to
             * return "schily" for the SCG_AUTHOR request.
             */
            case SCG_AUTHOR:
                  return (_usal_auth_cdrkit);
            case SCG_SCCS_ID:
                  return (__sccsid);
            }
      }
      return ((char *)0);
}

static int
usalo_help(SCSI *usalp, FILE *f)
{
      __usal_help(f, "ASPI", "Generic transport independent SCSI",
            "", "bus,target,lun", "1,2,0", TRUE, FALSE);
      return (0);
}

static int
usalo_open(SCSI *usalp, char *device)
{
      int   busno = usal_scsibus(usalp);
      int   tgt   = usal_target(usalp);
      int   tlun  = usal_lun(usalp);

      if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
            errno = EINVAL;
            if (usalp->errstr)
                  snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
                        "Illegal value for busno, target or lun '%d,%d,%d'",
                        busno, tgt, tlun);
            return (-1);
      }

      if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) {
            errno = EINVAL;
            if (usalp->errstr)
                  snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
                        "Open by 'devname' not supported on this OS");
            return (-1);
      }

      if (usalp->local == NULL) {
            usalp->local = malloc(sizeof (struct usal_local));
            if (usalp->local == NULL)
                  return (0);
      }

      if (!open_driver(usalp))      /* Try to open ASPI-Router */
            return (-1);
      atexit(exit_func);      /* Install Exit Function which closes the ASPI-Router */

      /*
       * Success after all
       */
      return (1);
}

static int
usalo_close(SCSI *usalp)
{
      exit_func();
      return (0);
}

static long
usalo_maxdma(SCSI *cgp, long amt)
{
      long maxdma = MAX_DMA_OS2;
      return (maxdma);
}

static void *
usalo_getbuf(SCSI *usalp, long amt)
{
      ULONG rc;

#ifdef DEBUG
      fprintf((FILE *)usalp->errfile, "usalo_getbuf: %ld bytes\n", amt);
#endif
      rc = DosAllocMem(&buffer, amt, OBJ_TILE | PAG_READ | PAG_WRITE | PAG_COMMIT);

      if (rc) {
            fprintf((FILE *)usalp->errfile, "Cannot allocate buffer.\n");
            return ((void *)0);
      }
      usalp->bufbase = buffer;

#ifdef DEBUG
      fprintf((FILE *)usalp->errfile, "Buffer allocated at: 0x%x\n", usalp->bufbase);
#endif

      /* Lock memory */
      if (init_buffer(usalp->bufbase))
            return (usalp->bufbase);

      fprintf((FILE *)usalp->errfile, "Cannot lock memory buffer.\n");
      return ((void *)0); /* Error */
}

static void
usalo_freebuf(SCSI *usalp)
{
      if (usalp->bufbase && DosFreeMem(usalp->bufbase)) {
            fprintf((FILE *)usalp->errfile,
            "Cannot free buffer memory for ASPI-Router!\n"); /* Free our memory buffer if not already done */
      }
      if (buffer == usalp->bufbase)
            buffer = NULL;
      usalp->bufbase = NULL;
}

static BOOL
usalo_havebus(SCSI *usalp, int busno)
{
      register int      t;
      register int      l;

      if (busno < 0 || busno >= MAX_SCG)
            return (FALSE);

      return (TRUE);
}

static int
usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun)
{
      if (busno < 0 || busno >= MAX_SCG ||
          tgt < 0 || tgt >= MAX_TGT ||
          tlun < 0 || tlun >= MAX_LUN)
            return (-1);

      /*
       * Return fake
       */
      return (1);
}


static int
usalo_initiator_id(SCSI *usalp)
{
      return (-1);
}

static int
usalo_isatapi(SCSI *usalp)
{
      return (FALSE);
}


static int
usalo_reset(SCSI *usalp, int what)
{
      ULONG rc;                     /* return value */
      ULONG cbreturn;
      ULONG cbParam;
      BOOL  success;
static      SRB   SRBlock;                /* XXX makes it non reentrant */

      if (what == SCG_RESET_NOP)
            return (0);
      if (what != SCG_RESET_BUS) {
            errno = EINVAL;
            return (-1);
      }
      /*
       * XXX Does this reset TGT or BUS ???
       */
      SRBlock.cmd       = SRB_Reset;            /* reset device         */
      SRBlock.ha_num          = usal_scsibus(usalp);  /* host adapter number  */
      SRBlock.flags           = SRB_Post;       /* posting enabled      */
      SRBlock.u.res.target    = usal_target(usalp);   /* target id            */
      SRBlock.u.res.lun = usal_lun(usalp);      /* target LUN           */

      rc = DosDevIOCtl(driver_handle, 0x92, 0x02, (void*) &SRBlock, sizeof (SRB), &cbParam,
                  (void*) &SRBlock, sizeof (SRB), &cbreturn);
      if (rc) {
            fprintf((FILE *)usalp->errfile,
                        "DosDevIOCtl() failed in resetDevice.\n");
            return (1);             /* DosDevIOCtl failed */
      } else {
            success = wait_post(40000);   /** wait for SRB being processed */
            if (success)
                  return (2);
      }
      if (SRBlock.status != SRB_Done)
            return (3);
#ifdef DEBUG
      fprintf((FILE *)usalp->errfile,
            "resetDevice of host: %d target: %d lun: %d successful.\n", usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
      fprintf((FILE *)usalp->errfile,
            "SRBlock.ha_status: 0x%x, SRBlock.target_status: 0x%x, SRBlock.satus: 0x%x\n",
                        SRBlock.u.cmd.ha_status, SRBlock.u.cmd.target_status, SRBlock.status);
#endif
      return (0);
}

/*
 * Set error flags
 */
static void
set_error(SRB *srb, struct usal_cmd *sp)
{
      switch (srb->status) {

      case SRB_InvalidCmd:          /* 0x80 Invalid SCSI request      */
      case SRB_InvalidHA:           /* 0x81 Invalid host adapter number */
      case SRB_BadDevice:           /* 0x82 SCSI device not installed   */
            sp->error = SCG_FATAL;
            sp->ux_errno = EINVAL;  /* Should we ever return != EIO         */
            sp->ux_errno = EIO;
            break;


      case SRB_Busy:                /* 0x00 SCSI request in progress    */
      case SRB_Aborted:       /* 0x02 SCSI aborted by host      */
      case SRB_BadAbort:            /* 0x03 Unable to abort SCSI request */
      case SRB_Error:               /* 0x04 SCSI request completed with error */
      default:
            sp->error = SCG_RETRYABLE;
            sp->ux_errno = EIO;
            break;
      }
}

static int
usalo_send(SCSI *usalp)
{
      struct usal_cmd   *sp = usalp->scmd;
      ULONG rc;                     /* return value */
static      SRB   SRBlock;                /* XXX makes it non reentrant */
      Ulong cbreturn;
      Ulong cbParam;
      UCHAR*      ptr;

      if (usalp->fd < 0) {                /* Set in usalo_open() */
            sp->error = SCG_FATAL;
            return (0);
      }

      if (sp->cdb_len > sizeof (SRBlock.u.cmd.cdb_st)) { /* commandsize too big */
            sp->error = SCG_FATAL;
            sp->ux_errno = EINVAL;
            fprintf((FILE *)usalp->errfile,
                  "sp->cdb_len > SRBlock.u.cmd.cdb_st. Fatal error in usalo_send, exiting...\n");
            return (-1);
      }

      /* clear command block */
      fillbytes((caddr_t)&SRBlock.u.cmd.cdb_st, sizeof (SRBlock.u.cmd.cdb_st), '\0');
      /* copy cdrecord command into SRB */
      movebytes(&sp->cdb, &SRBlock.u.cmd.cdb_st, sp->cdb_len);

      /* Build SRB command block */
      SRBlock.cmd = SRB_Command;
      SRBlock.ha_num = usal_scsibus(usalp);     /* host adapter number */

      SRBlock.flags = SRB_Post;           /* flags */

      SRBlock.u.cmd.target    = usal_target(usalp); /* Target SCSI ID */
      SRBlock.u.cmd.lun = usal_lun(usalp); /* Target SCSI LUN */
      SRBlock.u.cmd.data_len  = sp->size; /* # of bytes transferred */
      SRBlock.u.cmd.data_ptr  = 0;        /* pointer to data buffer */
      SRBlock.u.cmd.sense_len = sp->sense_len; /* length of sense buffer */

      SRBlock.u.cmd.link_ptr  = 0;        /* pointer to next SRB */
      SRBlock.u.cmd.cdb_len   = sp->cdb_len;    /* SCSI command length */

      /* Specify direction */
      if (sp->flags & SCG_RECV_DATA) {
            SRBlock.flags |= SRB_Read;
      } else {
            if (sp->size > 0) {
                  SRBlock.flags |= SRB_Write;
                  if (usalp->bufbase != sp->addr) { /* Copy only if data not in ASPI-Mem */
                        movebytes(sp->addr, usalp->bufbase, sp->size);
                  }
            } else {
                  SRBlock.flags |= SRB_NoTransfer;
            }
      }
      sp->error   = SCG_NO_ERROR;
      sp->sense_count   = 0;
      sp->u_scb.cmd_scb[0] = 0;
      sp->resid   = 0;

      /* execute SCSI   command */
      rc = DosDevIOCtl(driver_handle, 0x92, 0x02,
                  (void*) &SRBlock, sizeof (SRB), &cbParam,
                  (void*) &SRBlock, sizeof (SRB), &cbreturn);

      if (rc) {         /* An error occured */
            fprintf((FILE *)usalp->errfile,
                        "DosDevIOCtl() in sendCommand failed.\n");
            sp->error = SCG_FATAL;
            sp->ux_errno = EIO;     /* Später vielleicht errno einsetzen */
            return (rc);
      } else {
            /* Wait until the command is processed */
            rc = wait_post(sp->timeout*1000);
            if (rc) {   /* An error occured */
                  if (rc == 640) {
                        /* Timeout */
                        sp->error = SCG_TIMEOUT;
                        sp->ux_errno = EIO;
                        fprintf((FILE *)usalp->errfile,
                                    "Timeout during SCSI-Command.\n");
                        return (1);
                  }
                  sp->error = SCG_FATAL;
                  sp->ux_errno = EIO;
                  fprintf((FILE *)usalp->errfile,
                              "Fatal Error during DosWaitEventSem().\n");
                  return (1);
            }

            /* The command is processed */
            if (SRBlock.status == SRB_Done) {   /* succesful completion */
#ifdef DEBUG
                  fprintf((FILE *)usalp->errfile,
                        "Command successful finished. SRBlock.status=0x%x\n\n", SRBlock.status);
#endif
                  sp->sense_count = 0;
                  sp->resid = 0;
                  if (sp->flags & SCG_RECV_DATA) {    /* We read data */
                        if (sp->addr && sp->size) {
                              if (usalp->bufbase != sp->addr)     /* Copy only if data not in ASPI-Mem */
                                    movebytes(usalp->bufbase, sp->addr, SRBlock.u.cmd.data_len);
                              ptr = (UCHAR*)sp->addr;
                              sp->resid = sp->size - SRBlock.u.cmd.data_len; /*nicht übertragene bytes. Korrekt berechnet???*/
                        }
                  }     /* end of if (sp->flags & SCG_RECV_DATA) */
                  if (SRBlock.u.cmd.target_status == SRB_CheckStatus) { /* Sense data valid */
                        sp->sense_count   = (int)SRBlock.u.cmd.sense_len;
                        if (sp->sense_count > sp->sense_len)
                              sp->sense_count = sp->sense_len;

                        ptr = (UCHAR*)&SRBlock.u.cmd.cdb_st;
                        ptr += SRBlock.u.cmd.cdb_len;

                        fillbytes(&sp->u_sense.Sense, sizeof (sp->u_sense.Sense), '\0');
                        movebytes(ptr, &sp->u_sense.Sense, sp->sense_len);

                        sp->u_scb.cmd_scb[0] = SRBlock.u.cmd.target_status;
                        sp->ux_errno = EIO;     /* Später differenzieren? */
                  }
                  return (0);
            }
            /* SCSI-Error occured */
            set_error(&SRBlock, sp);

            if (SRBlock.u.cmd.target_status == SRB_CheckStatus) { /* Sense data valid */
                  sp->sense_count   = (int)SRBlock.u.cmd.sense_len;
                  if (sp->sense_count > sp->sense_len)
                        sp->sense_count = sp->sense_len;

                  ptr = (UCHAR*)&SRBlock.u.cmd.cdb_st;
                  ptr += SRBlock.u.cmd.cdb_len;

                  fillbytes(&sp->u_sense.Sense, sizeof (sp->u_sense.Sense), '\0');
                  movebytes(ptr, &sp->u_sense.Sense, sp->sense_len);

                  sp->u_scb.cmd_scb[0] = SRBlock.u.cmd.target_status;
            }
            if (sp->flags & SCG_RECV_DATA) {
                  if (sp->addr && sp->size) {
                        if (usalp->bufbase != sp->addr)     /* Copy only if data not in ASPI-Mem */
                              movebytes(usalp->bufbase, sp->addr, SRBlock.u.cmd.data_len);
                  }
            }
#ifdef      really
            sp->resid   = SRBlock.u.cmd.data_len; /* XXXXX Got no Data ????? */
#else
            sp->resid   = sp->size - SRBlock.u.cmd.data_len;
#endif
            return (1);
      }
}

/***************************************************************************
 *                                                       *
 *  BOOL open_driver()                                         *
 *                                                       *
 *  Opens the ASPI Router device driver and sets device_handle.            *
 *  Returns:                                                   *
 *    TRUE - Success                                           *
 *    FALSE - Unsuccessful opening of device driver                  *
 *                                                       *
 *  Preconditions: ASPI Router driver has be loaded                  *
 *                                                       *
 ***************************************************************************/
static BOOL
open_driver(SCSI *usalp)
{
      ULONG rc;               /* return value */
      ULONG ActionTaken;            /* return value   */
      USHORT      openSemaReturn;         /* return value   */
      ULONG cbreturn;
      ULONG cbParam;

      if (driver_handle)            /* ASPI-Router already opened */
            return (TRUE);

      rc = DosOpen((PSZ) "aspirou$",      /* open driver*/
                  &driver_handle,
                  &ActionTaken,
                  0,
                  0,
                  FILE_OPEN,
                  OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE,
                  NULL);
      if (rc) {
            fprintf((FILE *)usalp->errfile,
                        "Cannot open ASPI-Router!\n");

            return (FALSE);         /* opening failed -> return false*/
      }

      /* Init semaphore */
      if (DosCreateEventSem(NULL, &postSema,    /* create event semaphore */
                        DC_SEM_SHARED, 0)) {
            DosClose(driver_handle);
            fprintf((FILE *)usalp->errfile,
                        "Cannot create event semaphore!\n");

            return (FALSE);
      }
      rc = DosDevIOCtl(driver_handle, 0x92, 0x03,     /* pass semaphore handle */
                  (void*) &postSema, sizeof (HEV), /* to driver          */
                  &cbParam, (void*) &openSemaReturn,
                  sizeof (USHORT), &cbreturn);

      if (rc||openSemaReturn) {                 /* Error */
            DosCloseEventSem(postSema);
            DosClose(driver_handle);
            return (FALSE);
      }
      return (TRUE);
}

/***************************************************************************
 *                                                       *
 *  BOOL close_driver()                                        *
 *                                                       *
 *  Closes the device driver                                   *
 *  Returns:                                                   *
 *    TRUE - Success                                           *
 *    FALSE - Unsuccessful closing of device driver                  *
 *                                                       *
 *  Preconditions: ASPI Router driver has be opened with open_driver       *
 *                                                       *
 ***************************************************************************/
static BOOL
close_driver()
{
      ULONG rc;                     /* return value */

      if (driver_handle) {
            rc = DosClose(driver_handle);
            if (rc)
                  return (FALSE);         /* closing failed -> return false */
            driver_handle = 0;
            if (DosCloseEventSem(postSema))
                  fprintf(stderr, "Cannot close event semaphore!\n");
            if (buffer && DosFreeMem(buffer)) {
                  fprintf(stderr,
                  "Cannot free buffer memory for ASPI-Router!\n"); /* Free our memory buffer if not already done */
            }
            buffer = NULL;
      }
      return (TRUE);
}

static ULONG
wait_post(ULONG ulTimeOut)
{
      ULONG count = 0;
      ULONG rc;                           /* return value */

/*    rc = DosWaitEventSem(postSema, -1);*/           /* wait forever*/
      rc = DosWaitEventSem(postSema, ulTimeOut);
      DosResetEventSem(postSema, &count);
      return (rc);
}

static BOOL
init_buffer(void *mem)
{
      ULONG rc;                           /* return value */
      USHORT lockSegmentReturn;                 /* return value */
      Ulong cbreturn;
      Ulong cbParam;

      rc = DosDevIOCtl(driver_handle, 0x92, 0x04,     /* pass buffers pointer */
                  (void*) mem, sizeof (void*),  /* to driver */
                  &cbParam, (void*) &lockSegmentReturn,
                  sizeof (USHORT), &cbreturn);
      if (rc)
            return (FALSE);                     /* DosDevIOCtl failed */
      if (lockSegmentReturn)
            return (FALSE);                     /* Driver could not lock segment */
      return (TRUE);
}
#define     sense u_sense.Sense

Generated by  Doxygen 1.6.0   Back to index