diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2012-12-31 05:04:42 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2012-12-31 05:04:42 +0400 |
commit | 71dc8760ff4de5f365330d1bc571d934deb54af9 (patch) | |
tree | 7346d42a282562a3937d82307012b5857d642ce6 /libusal/scsi-os2.c | |
download | cdrkit-941fb342494d2b61ef5fd1870a4fa695d1c7fc69.tar.gz |
Imported Upstream version 1.1.11upstream/1.1.11upstream
Diffstat (limited to 'libusal/scsi-os2.c')
-rw-r--r-- | libusal/scsi-os2.c | 630 |
1 files changed, 630 insertions, 0 deletions
diff --git a/libusal/scsi-os2.c b/libusal/scsi-os2.c new file mode 100644 index 0000000..5758b8d --- /dev/null +++ b/libusal/scsi-os2.c @@ -0,0 +1,630 @@ +/* + * 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 |