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 | |
download | cdrkit-941fb342494d2b61ef5fd1870a4fa695d1c7fc69.tar.gz |
Imported Upstream version 1.1.11upstream/1.1.11upstream
Diffstat (limited to 'libusal')
46 files changed, 24383 insertions, 0 deletions
diff --git a/libusal/CMakeLists.txt b/libusal/CMakeLists.txt new file mode 100644 index 0000000..b6fc8e4 --- /dev/null +++ b/libusal/CMakeLists.txt @@ -0,0 +1,10 @@ +PROJECT (LIBSCG C) +INCLUDE_DIRECTORIES(../include ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}/include) +include(../include/AddScgBits.cmake) +ADD_DEFINITIONS(-DUSE_RCMD_RSH) + +#SET(LIBSCG_SRCS rdummy.c usalsettarget.c usaltimes.c scsi-linux-ata.c scsi-linux-pg.c scsi-linux-sg.c scsierrs.c scsihack.c scsihelp.c scsiopen.c scsitransp.c) +SET(LIBSCG_SRCS usalsettarget.c usaltimes.c scsierrs.c scsihack.c scsihelp.c scsiopen.c scsitransp.c scsi-remote.c) +LINK_DIRECTORIES(../librols) +ADD_LIBRARY (usal STATIC ${LIBSCG_SRCS}) +TARGET_LINK_LIBRARIES(usal ${SCG_SELF_LIBS}) diff --git a/libusal/pg.h b/libusal/pg.h new file mode 100644 index 0000000..8e8bf18 --- /dev/null +++ b/libusal/pg.h @@ -0,0 +1,75 @@ +/* + * 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. + * + */ + +/* pg.h (c) 1998 Grant R. Guenther <grant@torque.net> + Under the terms of the GNU public license + + + pg.h defines the user interface to the generic ATAPI packet + command driver for parallel port ATAPI devices (pg). The + driver is loosely modelled after the generic SCSI driver, sg, + although the actual interface is different. + + The pg driver provides a simple character device interface for + sending ATAPI commands to a device. With the exception of the + ATAPI reset operation, all operations are performed by a pair + of read and write operations to the appropriate /dev/pgN device. + A write operation delivers a command and any outbound data in + a single buffer. Normally, the write will succeed unless the + device is offline or malfunctioning, or there is already another + command pending. If the write succeeds, it should be followed + immediately by a read operation, to obtain any returned data and + status information. A read will fail if there is no operation + in progress. + + As a special case, the device can be reset with a write operation, + and in this case, no following read is expected, or permitted. + + There are no ioctl() operations. Any single operation + may transfer at most PG_MAX_DATA bytes. Note that the driver must + copy the data through an internal buffer. In keeping with all + current ATAPI devices, command packets are assumed to be exactly + 12 bytes in length. + + To permit future changes to this interface, the headers in the + read and write buffers contain a single character "magic" flag. + Currently this flag must be the character "P". + +*/ + +#define PG_MAGIC 'P' +#define PG_RESET 'Z' +#define PG_COMMAND 'C' + +#define PG_MAX_DATA 32768 + +struct pg_write_hdr { + + char magic; /* == PG_MAGIC */ + char func; /* PG_RESET or PG_COMMAND */ + int dlen; /* number of bytes expected to transfer */ + int timeout; /* number of seconds before timeout */ + char packet[12]; /* packet command */ + +}; + +struct pg_read_hdr { + + char magic; /* == PG_MAGIC */ + char scsi; /* "scsi" status == sense key */ + int dlen; /* size of device transfer request */ + int duration; /* time in seconds command took */ + char pad[12]; /* not used */ + +}; + +/* end of pg.h */ diff --git a/libusal/rdummy.c b/libusal/rdummy.c new file mode 100644 index 0000000..4457e00 --- /dev/null +++ b/libusal/rdummy.c @@ -0,0 +1,49 @@ +/* + * 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. + * + */ + +/* @(#)rdummy.c 1.1 00/08/26 Copyright 2000 J. Schilling */ +/* + * usal Library + * dummy remote ops + * + * Copyright (c) 2000 J. Schilling + */ +/* + * 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. + */ + +#include <mconfig.h> +#include <standard.h> +#include <schily.h> + +#include <usal/scsitransp.h> + +usal_ops_t *usal_remote(void); + +EXPORT usal_ops_t * +usal_remote() +{ +extern usal_ops_t usal_remote_ops; + + return (&usal_remote_ops); +} diff --git a/libusal/scsi-aix.c b/libusal/scsi-aix.c new file mode 100644 index 0000000..a7b4be6 --- /dev/null +++ b/libusal/scsi-aix.c @@ -0,0 +1,428 @@ +/* + * 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-aix.c 1.36 04/01/14 Copyright 1997 J. Schilling */ +/* + * Interface for the AIX generic SCSI implementation. + * + * This is a hack, that tries to emulate the functionality + * of the usal driver. + * + * 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. + * + * Copyright (c) 1997 J. Schilling + */ +/* + * 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. + */ + +#include <sys/scdisk.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-aix.c-1.36"; /* The version for this transport*/ + + +#define MAX_SCG 16 /* Max # of SCSI controllers */ +#define MAX_TGT 16 +#define MAX_LUN 8 + +struct usal_local{ + short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN]; +}; +#define usallocal(p) ((struct usal_local*)((p)->local)) + +#define MAX_DMA_AIX (64*1024) + +static int do_usal_cmd(SCSI *usalp, struct usal_cmd *sp); +static int do_usal_sense(SCSI *usalp, struct usal_cmd *sp); + +/* + * 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, "DKIOCMD", "SCSI transport for targets known by AIX drivers", + "", "bus,target,lun or UNIX device", "1,2,0 or /dev/rcd0@", FALSE, TRUE); + 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); + register int f; + register int b; + register int t; + register int l; + register int nopen = 0; + char devname[32]; + + 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 (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } + + if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) + goto openbydev; + + if (busno >= 0 && tgt >= 0 && tlun >= 0) { + + snprintf(devname, sizeof (devname), "/dev/rcd%d", tgt); + f = openx(devname, 0, 0, SC_DIAGNOSTIC); + if (f < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'. Specify device number (1 for cd1) as target (1,0)", + devname); + return (0); + } + usallocal(usalp)->usalfiles[busno][tgt][tlun] = f; + return (1); + } else { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Unable to scan on AIX"); + return (0); + } +openbydev: + if (device != NULL && *device != '\0' && busno >= 0 && tgt >= 0 && tlun >= 0) { + f = openx(device, 0, 0, SC_DIAGNOSTIC); + if (f < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", + devname); + return (0); + } + + usallocal(usalp)->usalfiles[busno][tgt][tlun] = f; + usal_settarget(usalp, busno, tgt, tlun); + + return (++nopen); + } + return (nopen); +} + +static int +usalo_close(SCSI *usalp) +{ + register int f; + register int b; + register int t; + register int l; + + if (usalp->local== NULL) + return (-1); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + f = usallocal(usalp)->usalfiles[b][t][l]; + if (f >= 0) + close(f); + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + return (MAX_DMA_AIX); +} + +#define palign(x, a) (((char *)(x)) + ((a) - 1 - (((UIntptr_t)((x)-1))%(a)))) + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ +/* assume having a modern AIX here */ +#ifdef HAVE_ALLOCA_H + usalp->bufbase = (void *)valloc((size_t)amt); + return (usalp->bufbase); +#else + void *ret; + int pagesize = getpagesize(); + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + /* + * Damn AIX is a paged system but has no valloc() + */ + usalp->bufbase = ret = malloc((size_t)(amt+pagesize)); + if (ret == NULL) + return (ret); + ret = palign(ret, pagesize); + return (ret); +#endif +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + 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); + + if (usalp->local == NULL) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if (usallocal(usalp)->usalfiles[busno][t][l] >= 0) + return (TRUE); + } + return (FALSE); +} + +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); + + if (usalp->local == NULL) + return (-1); + + return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]); +} + +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) +{ + if (what == SCG_RESET_NOP) + return (0); + if (what != SCG_RESET_BUS) { + errno = EINVAL; + return (-1); + } + /* + * XXX Does this reset TGT or BUS ??? + */ + return (ioctl(usalp->fd, SCIORESET, IDLUN(usal_target(usalp), usal_lun(usalp)))); +} + +static int +do_usal_cmd(SCSI *usalp, struct usal_cmd *sp) +{ + struct sc_iocmd req; + int ret; + + if (sp->cdb_len > 12) + comerrno(EX_BAD, "Can't do %d byte command.\n", sp->cdb_len); + + fillbytes(&req, sizeof (req), '\0'); + + req.flags = SC_ASYNC; + if (sp->flags & SCG_RECV_DATA) { + req.flags |= B_READ; + } else if (sp->size > 0) { + req.flags |= B_WRITE; + } + req.data_length = sp->size; + req.buffer = sp->addr; + req.timeout_value = sp->timeout; + req.command_length = sp->cdb_len; + + movebytes(&sp->cdb, req.scsi_cdb, 12); + errno = 0; + ret = ioctl(usalp->fd, DKIOCMD, &req); + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, "ret: %d errno: %d (%s)\n", ret, errno, errmsgstr(errno)); + fprintf((FILE *)usalp->errfile, "data_length: %d\n", req.data_length); + fprintf((FILE *)usalp->errfile, "buffer: 0x%X\n", req.buffer); + fprintf((FILE *)usalp->errfile, "timeout_value: %d\n", req.timeout_value); + fprintf((FILE *)usalp->errfile, "status_validity: %d\n", req.status_validity); + fprintf((FILE *)usalp->errfile, "scsi_bus_status: 0x%X\n", req.scsi_bus_status); + fprintf((FILE *)usalp->errfile, "adapter_status: 0x%X\n", req.adapter_status); + fprintf((FILE *)usalp->errfile, "adap_q_status: 0x%X\n", req.adap_q_status); + fprintf((FILE *)usalp->errfile, "q_tag_msg: 0x%X\n", req.q_tag_msg); + fprintf((FILE *)usalp->errfile, "flags: 0X%X\n", req.flags); + } + if (ret < 0) { + sp->ux_errno = geterrno(); + /* + * Check if SCSI command cound not be send at all. + */ + if (sp->ux_errno == ENOTTY || sp->ux_errno == ENXIO || + sp->ux_errno == EINVAL || sp->ux_errno == EACCES) { + return (-1); + } + } else { + sp->ux_errno = 0; + } + ret = 0; + sp->sense_count = 0; + sp->resid = 0; /* AIX is the same rubbish as Linux here */ + + fillbytes(&sp->scb, sizeof (sp->scb), '\0'); + fillbytes(&sp->u_sense.cmd_sense, sizeof (sp->u_sense.cmd_sense), '\0'); + + if (req.status_validity == 0) { + sp->error = SCG_NO_ERROR; + return (0); + } + if (req.status_validity & 1) { + sp->u_scb.cmd_scb[0] = req.scsi_bus_status; + sp->error = SCG_RETRYABLE; + } + if (req.status_validity & 2) { + if (req.adapter_status & SC_NO_DEVICE_RESPONSE) { + sp->error = SCG_FATAL; + + } else if (req.adapter_status & SC_CMD_TIMEOUT) { + sp->error = SCG_TIMEOUT; + + } else if (req.adapter_status != 0) { + sp->error = SCG_RETRYABLE; + } + } + + return (ret); +} + +static int +do_usal_sense(SCSI *usalp, struct usal_cmd *sp) +{ + int ret; + struct usal_cmd s_cmd; + + fillbytes((caddr_t)&s_cmd, sizeof (s_cmd), '\0'); + s_cmd.addr = sp->u_sense.cmd_sense; + s_cmd.size = sp->sense_len; + s_cmd.flags = SCG_RECV_DATA|SCG_DISRE_ENA; + s_cmd.cdb_len = SC_G0_CDBLEN; + s_cmd.sense_len = CCS_SENSE_LEN; + s_cmd.cdb.g0_cdb.cmd = SC_REQUEST_SENSE; + s_cmd.cdb.g0_cdb.lun = sp->cdb.g0_cdb.lun; + s_cmd.cdb.g0_cdb.count = sp->sense_len; + ret = do_usal_cmd(usalp, &s_cmd); + + if (ret < 0) + return (ret); + if (s_cmd.u_scb.cmd_scb[0] & 02) { + /* XXX ??? Check condition on request Sense ??? */ + } + sp->sense_count = sp->sense_len - s_cmd.resid; + return (ret); +} + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + int ret; + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + ret = do_usal_cmd(usalp, sp); + if (ret < 0) + return (ret); + if (sp->u_scb.cmd_scb[0] & 02) + ret = do_usal_sense(usalp, sp); + return (ret); +} diff --git a/libusal/scsi-amigaos.c b/libusal/scsi-amigaos.c new file mode 100644 index 0000000..991a4ab --- /dev/null +++ b/libusal/scsi-amigaos.c @@ -0,0 +1,771 @@ +/* + * 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-amigaos.c 1.6 04/01/14 Copyright 1997,2000-2003 J. Schilling */ +/* + * Interface for the AmigaOS generic SCSI implementation. + * + * 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. + * + * Copyright (c) 1997, 2000-2003 J. Schilling + * AmigaOS support code written by T. Langer + */ +/* + * 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. + */ + +#define BOOL int + +#include <strdefs.h> +#include <exec/ports.h> +#include <exec/io.h> +#include <exec/errors.h> +#include <devices/scsidisk.h> +#include <devices/timer.h> +#include <exec/semaphores.h> +#include <exec/memory.h> +#include <exec/execbase.h> +#include <clib/exec_protos.h> +#include <clib/alib_protos.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-amigaos.c-1.6"; /* The version for this transport */ +static char _usal_auth[] = "T. Langer"; + +#define MAX_SCG 8 /* Max # of SCSI controllers */ +#define MAX_TGT 8 +#define MAX_LUN 8 +#define MAX_DEV MAX_SCG*MAX_TGT*MAX_LUN + +struct usal_local{ + int usalfiles[MAX_SCG][MAX_TGT][MAX_LUN]; +}; + +#define usallocal(p) ((struct usal_local*)((p)->local)) + +#define MAX_DMA_AMIGAOS (64*1024) + +static struct IOReq { + struct IOStdReq *ioReq; + int ref_count; +} request[MAX_DEV]; + +static char *devs[MAX_SCG]; +static struct MsgPort *ioMsgPort = NULL; +static struct timerequest *timer_io = NULL; +static struct MsgPort *timerMsgPort = NULL; +static int initialized = 0; +static int last_bus = -1; +/* my private var: for debug purpose only */ +static int ami_debug = 0; + +extern struct ExecBase *SysBase; +#define IOERR_TIMEOUT (-8) +#define CHECK_CONDITION 0x02 +#define DUNIT(b, t, l) (100 * b) + (10 * (l < 0 ? 0:l)) + t + +static void amiga_init(void); +static int amiga_open_scsi(int bus, int tgt, int lun, SCSI *usalp); +static void amiga_close_scsi(int fd); +static void amiga_close_scsi_all(void); +static void amiga_scan_devices(void); +static int amiga_find_device(char *device); +static int amiga_open_timer(void); +static void amiga_close_timer(void); +static int amiga_get_scsi_bus(char *device); + +/* + * 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);*/ + return (_usal_auth); + case SCG_SCCS_ID: + return (__sccsid); + } + } + return ((char *)0); +} + +static int +usalo_help(SCSI *usalp, FILE *f) +{ + __usal_help(f, "Amiga SCSI", "Generic SCSI", + "", "bus,target,lun or xxx.device:b,t,l", "1,2,0 or scsi.device: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); + register int f; + register int b; + register int t; + register int l; + register int nopen = 0; + + if (initialized == 0) { + amiga_init(); + initialized = 1; + } + + 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 (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + usallocal(usalp)->usalfiles[b][t][l] = -1; + } + } + } + } + + if (device == NULL || *device == '\0') { + + if (last_bus == -1) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "No scsi device found"); + return (-1); + } + if (busno < 0 && tgt < 0 && tlun < 0) { + /* cdrecord -scanbus */ + for (b = 0; b <= last_bus; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + f = amiga_open_scsi(b, t, l, usalp); + if (f != -1) { + usallocal(usalp)->usalfiles[b][t][l] = f; + nopen++; + } + } + } + } + } else { + /* cdrecord [-scanbus] dev=b,t,l */ + f = amiga_open_scsi(busno, tgt, tlun, usalp); + if (f != -1) { + usallocal(usalp)->usalfiles[busno][tgt][tlun] = f; + nopen++; + } + } + } else { + if (busno < 0 && tgt < 0 && tlun < 0) { + /* cdrecord -scanbus dev=xxx.device */ + b = amiga_get_scsi_bus(device); + if (b != -1) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + f = amiga_open_scsi(b, t, l, usalp); + if (f != -1) { + usallocal(usalp)->usalfiles[b][t][l] = f; + nopen++; + } + } + } + } else { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Scsi device %s not found", device); + } + } else { + /* cdrecord [-scanbus] dev=xxx.device:b,t,l */ + /* + * this is a special case, in which the scsi device is accessed just by + * name, bus parameter from the command is ignored. + */ + b = amiga_get_scsi_bus(device); + if (b != -1) { + f = amiga_open_scsi(b, tgt, tlun, usalp); + if (f != -1) { + usallocal(usalp)->usalfiles[busno][tgt][tlun] = f; + nopen++; + } + } else { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Scsi device %s not found", device); + } + } + } + + return (nopen); +} + +static int +usalo_close(SCSI *usalp) +{ + register int b; + register int t; + register int l; + + if (usalp->local == NULL) + return (-1); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + if (usallocal(usalp)->usalfiles[b][t][l] >= 0) + amiga_close_scsi(usallocal(usalp)->usalfiles[b][t][l]); + usallocal(usalp)->usalfiles[b][t][l] = -1; + } + } + } + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + return (MAX_DMA_AMIGAOS); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = valloc((size_t)(amt)); + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + 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); + + if (usalp->local == NULL) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if (usallocal(usalp)->usalfiles[busno][t][l] != -1) + return (TRUE); + } + return (FALSE); +} + +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); + + if (usalp->local == NULL) + return (-1); + + return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]); +} + +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) +{ + /* XXX Is there really no reset function on AmigaOS? */ + errno = EINVAL; + return (-1); +} + +static int +usalo_send(SCSI *usalp) +{ + register struct IOStdReq *ioreq = NULL; + struct SCSICmd Cmd; + int ret = 0; + struct usal_cmd *sp = usalp->scmd; + + sp->error = SCG_NO_ERROR; + sp->sense_count = 0; + sp->u_scb.cmd_scb[0] = 0; + sp->resid = 0; + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + ioreq = request[usalp->fd].ioReq; + if (ioreq == NULL) { + sp->error = SCG_FATAL; + return (0); + } + ioreq->io_Length = sizeof (struct SCSICmd); + ioreq->io_Data = &Cmd; + ioreq->io_Command = HD_SCSICMD; + + Cmd.scsi_Flags = SCSIF_AUTOSENSE; /* We set the SCSI cmd len */ + if (sp->flags & SCG_RECV_DATA) + Cmd.scsi_Flags |= SCSIF_READ; + else if (sp->size > 0) + Cmd.scsi_Flags |= SCSIF_WRITE; + + Cmd.scsi_Command = sp->cdb.cmd_cdb; + Cmd.scsi_CmdLength = sp->cdb_len; + Cmd.scsi_Data = (UWORD *) sp->addr; + Cmd.scsi_Length = sp->size; + Cmd.scsi_Actual = 0; + + Cmd.scsi_SenseData = sp->u_sense.cmd_sense; + Cmd.scsi_SenseLength = sp->sense_len; + Cmd.scsi_SenseActual = 0; + Cmd.scsi_Status = 0; + + do_scsi_cmd(ioreq, sp->timeout); + + fillbytes(&sp->scb, sizeof (sp->scb), '\0'); + sp->resid = Cmd.scsi_Length - Cmd.scsi_Actual; + + if (sp->resid < 0) + sp->resid = 0; + sp->sense_count = Cmd.scsi_SenseActual; + if (sp->sense_count < 0) + sp->sense_count; + + if (sp->sense_count > SCG_MAX_SENSE) + sp->sense_count = SCG_MAX_SENSE; + sp->u_scb.cmd_scb[0] = Cmd.scsi_Status; + + if (ioreq->io_Error) + sp->ux_errno = EIO; + + if (ami_debug) + printf("ioreq->io_Error: %ld; status %ld\n", ioreq->io_Error, Cmd.scsi_Status); + + switch (ioreq->io_Error) { + case 0: + sp->error = SCG_NO_ERROR; + break; + case IOERR_TIMEOUT: + sp->error = SCG_TIMEOUT; + break; + case HFERR_DMA: + case IOERR_UNITBUSY: + case HFERR_Phase: + case HFERR_Parity: + case HFERR_BadStatus: + if (Cmd.scsi_Status == CHECK_CONDITION) { + sp->error = SCG_NO_ERROR; + } else { + sp->error = SCG_RETRYABLE; + } + break; + default: + /* XXX was kann sonst noch passieren? */ + sp->error = SCG_FATAL; + break; + } + + return (ret); +} + +static int +do_scsi_cmd(struct IOStdReq *scsi_io, int timeout) +{ + ULONG scsi_flag = 0; + ULONG timer_flag = 0; + ULONG wait_sigs = 0; + ULONG wait_ret = 0; + int ret = 0; + + scsi_flag = 1L<<scsi_io->io_Message.mn_ReplyPort->mp_SigBit; + wait_sigs = scsi_flag; + + SetSignal(0L, scsi_flag); + SendIO((struct IORequest *)scsi_io); + if (timer_io) { + timer_flag = 1L<<timerMsgPort->mp_SigBit; + wait_sigs |= timer_flag; + timer_io->tr_time.tv_secs = timeout; + SetSignal(0L, timer_flag); + SendIO((struct IORequest *)timer_io); + } + + wait_ret = Wait(wait_sigs); + + if (wait_ret & scsi_flag) { + WaitIO((struct IORequest *)scsi_io); + if (timer_io) { + if (!CheckIO((struct IORequest *) timer_io)) { + AbortIO((struct IORequest *)timer_io); + WaitIO((struct IORequest *)timer_io); + } + } + } else if (wait_ret & timer_flag) { + WaitIO((struct IORequest *)timer_io); + if (!CheckIO((struct IORequest *) scsi_io)) { + AbortIO((struct IORequest *)scsi_io); + if (scsi_io->io_Error == IOERR_ABORTED) { + WaitIO((struct IORequest *)scsi_io); + } + } + scsi_io->io_Error = IOERR_TIMEOUT; + } + + return (scsi_io->io_Error); +} + +/*--------------------------------------------------------------------------*/ + +/* strlwr: seems not to be implemented in ixemul */ +static char * +strlwr(char *s) +{ + unsigned char *s1; + + s1 = (unsigned char *)s; + while (*s1) { + if ((*s1 > ('A'-1)) && (*s1 < ('Z'+1))) + *s1 += 'a'-'A'; + s1++; + } + return (s); +} + +/* + * amiga specific functions + */ +static void +amiga_init() +{ + memset(request, 0, sizeof (request)); + amiga_scan_devices(); + if (ami_debug) + printf("scanning bus. %ld device(s) found\n", last_bus + 1); + + atexit(amiga_close_scsi_all); +} + +static void +amiga_scan_devices() +{ + /* + * searching all known scsi devices + * for first there is only a (full) support for scsi.device and amithlon.device. + * This are devices i tested. + * All the other devices have to be specified by name (i.e. cdrecord dev=blabla.device:0,0,0) + * but didn't appear in the scanbus list. Later they should/may be also added to the + * main_dev_list (after testing). + */ + const char *main_dev_list[] = { "scsi.device", "amithlon.device", NULL }; + + int i; + char **main_dev; + + main_dev = (char **)main_dev_list; + while (*main_dev) { + if (last_bus == MAX_SCG - 1) + break; + if (amiga_find_device(*main_dev)) { + last_bus++; + devs[last_bus] = strdup(*main_dev); + for (i = 2; i < MAX_SCG; i++) { + char tmp[256]; + if (last_bus == MAX_SCG - 1) + break; + if (i == 2) { + sprintf(tmp, "2nd.%s", *main_dev); + } else if (i == 3) { + sprintf(tmp, "3rd.%s", *main_dev); + } else { + sprintf(tmp, "%ldth.%s", i, *main_dev); + } + if (amiga_find_device(tmp)) { + last_bus++; + devs[last_bus] = strdup(tmp); + } else { + break; + } + } + } + main_dev++; + } +} + +static void +amiga_close_scsi(int fd) +{ + if (request[fd].ref_count > 0) { + request[fd].ref_count--; + if (request[fd].ref_count == 0) { + CloseDevice((struct IORequest *) request[fd].ioReq); + DeleteStdIO(request[fd].ioReq); + request[fd].ioReq = NULL; + if (ami_debug) { + printf("closing device fd %ld\n", fd); + } + } + } +} + +static void +amiga_close_scsi_all() +{ + int i; + + for (i = 0; i < MAX_DEV; i++) { + if (request[i].ioReq != NULL) { + if (ami_debug) { + printf("closing device fd %ld\n", i); + } + CloseDevice((struct IORequest *) request[i].ioReq); + DeleteStdIO(request[i].ioReq); + request[i].ioReq = NULL; + } + } + + if (ioMsgPort) { + DeletePort(ioMsgPort); + ioMsgPort = NULL; + } + amiga_close_timer(); + + for (i = 0; i < MAX_SCG; i++) { + free(devs[i]); + } +} + +static int +amiga_open_scsi(int bus, int tgt, int lun, SCSI *usalp) +{ + int fd = bus * MAX_TGT * MAX_LUN + tgt * MAX_LUN + lun; + int unit = DUNIT(bus, tgt, lun); + char *dev = devs[bus]; + + if (dev == NULL) { + if (usalp->errstr) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "No scsi device found at bus %ld\n", bus); + } + return (-1); + } + + if (ioMsgPort == NULL) { + ioMsgPort = CreatePort(NULL, 0); + } + + if (ioMsgPort != NULL) { + if (request[fd].ioReq == NULL) { + request[fd].ioReq = CreateStdIO(ioMsgPort); + } + + if (request[fd].ioReq != NULL) { + if (ami_debug) + printf("trying %s, unit %ld\n", dev, unit); + if (OpenDevice(dev, unit, (struct IORequest *)request[fd].ioReq, 0L)) { + if (usalp->errstr) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open %s\n", dev); + } + if (request[fd].ref_count == 0) { + DeleteStdIO(request[fd].ioReq); + request[fd].ioReq = NULL; + } + fd = -1; + } else { + request[fd].ref_count++; + if (ami_debug) + printf("opening %s, unit %ld as fd %ld count %ld\n", dev, unit, fd, request[fd].ref_count); + } + } else { + if (usalp->errstr) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot create IOReq"); + } + } + } else { + if (usalp->errstr) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open Message Port"); + } + } + + return (fd); +} + +static int +amiga_open_timer() +{ + int ret = 0; + + /* we need the timer to catch scsi timeouts */ + if (timer_io == NULL) { + if (ami_debug) + printf("opening timer\n"); + + timerMsgPort = CreatePort(NULL, 0); + if (timerMsgPort) { + timer_io = (struct timerequest *)CreateExtIO(timerMsgPort, sizeof (struct timerequest)); + if (timer_io) { + if (OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *)timer_io, 0)) { + printf("Warning: can't open timer device\n"); + DeleteExtIO((struct IORequest *) timer_io); + DeletePort(timerMsgPort); + timer_io = NULL; + timerMsgPort = NULL; + ret = 1; + } else { + timer_io->tr_node.io_Command = TR_ADDREQUEST; + timer_io->tr_time.tv_micro = 0; + } + } else { + printf("Warning: can't create timer request\n"); + DeletePort(timerMsgPort); + timerMsgPort = NULL; + ret = 1; + } + } else { + printf("Warning: can't create timer port\n"); + ret = 1; + } + } + return (ret); +} + +static void +amiga_close_timer() +{ + if (timer_io) { + if (ami_debug) + printf("closing timer\n"); + + AbortIO((struct IORequest *) timer_io); + WaitIO((struct IORequest *) timer_io); + CloseDevice((struct IORequest *)timer_io); + DeleteExtIO((struct IORequest *) timer_io); + DeletePort(timerMsgPort); + timer_io = NULL; + timerMsgPort = NULL; + } +} + +static int +amiga_get_scsi_bus(char *device) +{ + int i; + char *tmp = strdup(device); + + strlwr(tmp); + for (i = 0; i <= last_bus; i++) { + if (strcmp(devs[i], tmp) == 0) { + return (i); + } + } + + if (amiga_find_device(tmp)) { + devs[i] = tmp; + last_bus = i; + return (i); + } + + return (-1); +} + +static int +amiga_find_device(char *device) +{ + char tmp[256]; + struct Node *DeviceLibNode = SysBase->DeviceList.lh_Head; + + if (ami_debug) + printf("looking for %s ", device); + + Forbid(); + while (DeviceLibNode->ln_Succ) { + DeviceLibNode = DeviceLibNode->ln_Succ; + strcpy(tmp, DeviceLibNode->ln_Name); + strlwr(tmp); + if (strcmp(tmp, device) == 0) { + if (ami_debug) + printf(" ... found\n"); + return (1); + } + } + Permit(); + + if (ami_debug) + printf(" ... not found\n"); + + return (0); +} diff --git a/libusal/scsi-apollo.c b/libusal/scsi-apollo.c new file mode 100644 index 0000000..c368468 --- /dev/null +++ b/libusal/scsi-apollo.c @@ -0,0 +1,550 @@ +/* + * 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-apollo.c 1.5 04/01/14 Copyright 1997,2000 J. Schilling */ +/* + * Code to support Apollo Domain/OS 10.4.1 + * + * Copyright (c) 1997,2000 J. Schilling + * Apollo support code written by Paul Walker. + */ +/* + * 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. + */ + +#include <apollo/base.h> +#include <apollo/scsi.h> +#include <assert.h> +#define DomainScsiTimeout 100000 + +/* + * 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-apollo.c-1.5"; /* The version for this transport */ + + +#define MAX_SCG 1 /* Max # of SCSI controllers */ +#define MAX_TGT 1 /* Max # of SCSI targets */ +#define MAX_LUN 1 /* Max # of SCSI logical units */ + +struct usal_local { + scsi_$handle_t handle; + unsigned char *DomainSensePointer; + short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN]; +}; + +#define usallocal(p) ((struct usal_local *)((p)->local)) + +#ifndef SG_MAX_SENSE +#define SG_MAX_SENSE 16 /* Too small for CCS / SCSI-2 */ +#endif /* But cannot be changed */ + +/* + * 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 ("Paul Walker"); + case SCG_SCCS_ID: + return (__sccsid); + } + } + return ((char *)0); +} + +static int +usalo_help(SCSI *usalp, FILE *f) +{ + __usal_help(f, "scsi_$do_command_2", "SCSI transport from Apollo DomainOS drivers", + "", "DomainOS driver name", "A DomainOS device node name", FALSE, TRUE); + return (0); +} + +static int +usalo_open(SCSI *usalp, char *device) +{ + register int nopen = 0; + status_$t status; + + if (usalp->debug > 1) + printf("Entered scsi_open, usalp=%p, device='%s'\n", usalp, device); + if (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + } + if (device == NULL || *device == '\0') { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, "Must give device name"); + return (0); + } + + scsi_$acquire(device, strlen(device), &usallocal(usalp)->handle, &status); + if (status.all) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, "Cannot open '%s', status %08x", device, status.all); + return (0); + } + /* + * Allocate the sense buffer + */ + usallocal(usalp)->DomainSensePointer = (Uchar *)valloc((size_t) (SCG_MAX_SENSE + getpagesize())); + assert(status.all == 0); + /* + * Wire the sense buffer + */ + scsi_$wire(usallocal(usalp)->handle, (caddr_t)(usallocal(usalp)->DomainSensePointer), SCG_MAX_SENSE, &status); + assert(status.all == 0); + + if (usallocal(usalp)->usalfiles[0][0][0] == -1) + usallocal(usalp)->usalfiles[0][0][0] = 1; + usal_settarget(usalp, 0, 0, 0); + return (++nopen); +} + +static int +usalo_close(SCSI *usalp) +{ + status_$t status; + + if (usalp->debug > 1) + printf("Entering scsi_close\n"); + scsi_$release(usallocal(usalp)->handle, &status); + /* + * should also unwire the sense buffer + */ + return (status.all); +} + + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + status_$t status; + scsi_$info_t info; + + scsi_$get_info(usallocal(usalp)->handle, sizeof (info), &info, &status); + if (status.all) { + /* + * Should have some better error handling here + */ + printf("scsi_$get_info returned %08x\n", status.all); + return (0); + } + return (info.max_xfer); +} + + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + void *ret; + + if (usalp->debug > 1) + printf("scsi_getbuf: %ld bytes\n", amt); + ret = valloc((size_t)amt); + if (ret == NULL) + return (ret); + usalp->bufbase = ret; + return (ret); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->debug > 1) + printf("Entering scsi_freebuf\n"); + + if (usalp->bufbase) + free(usalp->bufbase); + usalp->bufbase = NULL; +} + +static BOOL +usalo_havebus(SCSI *usalp, int busno) +{ + register int t; + register int l; + + if (usalp->debug > 1) + printf("Entered scsi_havebus: usalp=%p, busno=%d\n", usalp, busno); + + if (busno < 0 || busno >= MAX_SCG) + return (FALSE); + + if (usalp->local == NULL) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if (usallocal(usalp)->usalfiles[busno][t][l] >= 0) + return (TRUE); + } + return (FALSE); +} + +static int +usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun) +{ + if (usalp->debug > 1) + printf("Entered scsi_fileno: usalp=%p, busno=%d, tgt=%d, tlun=%d\n", usalp, busno, tgt, tlun); + if (busno < 0 || busno >= MAX_SCG || + tgt < 0 || tgt >= MAX_TGT || + tlun < 0 || tlun >= MAX_LUN) + return (-1); + + if (usalp->local == NULL) + return (-1); + if (usalp->debug > 1) + printf("exiting scsi_fileno, returning %d\n", usallocal(usalp)->usalfiles[busno][tgt][tlun]); + return ((int) usallocal(usalp)->usalfiles[busno][tgt][tlun]); +} + +static int +usalo_initiator_id(SCSI *usalp) +{ + if (usalp->debug > 1) + printf("Entering scsi_initiator\n"); + + return (-1); +} + +static int +usalo_isatapi(SCSI *usalp) +{ + return (FALSE); +} + +static int +usalo_reset(SCSI *usalp, int what) +{ + status_$t status; + + if (usalp->debug > 0) + printf("Entering scsi_reset\n"); + + if (what == SCG_RESET_NOP) + return (0); + + if (what == SCG_RESET_TGT) { + scsi_$reset_device(usallocal(usalp)->handle, &status); + if (status.all) + printf("Error - scsi_$reset_device failed, status is 0x%08x\n", status.all); + return (status.all); + } else { + errno = EINVAL; + return (-1); + } +} + +static void +scsi_do_sense(SCSI *usalp, struct usal_cmd *sp) +{ + scsi_$op_status_t op_status; + static scsi_$cdb_t sense_cdb; + static linteger sense_cdb_size; + static linteger sense_buffer_size; + static scsi_$operation_id_t sense_op_id; + static status_$t sense_status; + static pinteger sense_return_count; + int i; + + /* + * Issue the sense command (wire, issue, wait, unwire + */ + sense_buffer_size = sp->sense_len; + sense_cdb_size = SC_G0_CDBLEN; + memset(sense_cdb.all, 0, sense_cdb_size); /* Assuming Apollo sense */ + /* structure is correct */ + /* size */ + sense_cdb.g0.cmd = SC_REQUEST_SENSE; + sense_cdb.g0.lun = sp->cdb.g0_cdb.lun; + sense_cdb.g0.len = sp->sense_len; + scsi_$do_command_2(usallocal(usalp)->handle, sense_cdb, sense_cdb_size, (caddr_t) (usallocal(usalp)->DomainSensePointer), sense_buffer_size, scsi_read, &sense_op_id, &sense_status); + if (sense_status.all) { + printf("Error executing sense command, status is 0x%08x\n", sense_status.all); + } + scsi_$wait(usallocal(usalp)->handle, DomainScsiTimeout, true, sense_op_id, 1, &op_status, &sense_return_count, &sense_status); + /* + * Print the sense information if debug is on, or if the information is + * "unusual" + */ + if (usalp->debug > 0 || + /* + * I don't prinqqt info for sense codes 0, 2, 5, 6 because + * they aren't interesting + */ + (((u_char *) usallocal(usalp)->DomainSensePointer)[2] == 1) || + (((u_char *) usallocal(usalp)->DomainSensePointer)[2] == 3) || + (((u_char *) usallocal(usalp)->DomainSensePointer)[2] == 4) || + (((u_char *) usallocal(usalp)->DomainSensePointer)[2] >= 7)) { + printf(" Sense dump:\n"); + for (i = 0; i < sp->sense_len; i++) + printf(" %02x", ((u_char *) usallocal(usalp)->DomainSensePointer)[i]); + printf("\n"); + } + if (((u_char *) usallocal(usalp)->DomainSensePointer)[2] == 5) { + /* + * Illegal command + */ + printf("Illegal command detected, ASC=0x%02x, ASQ=0x%02x\n", ((u_char *) usallocal(usalp)->DomainSensePointer)[12], ((u_char *) usallocal(usalp)->DomainSensePointer)[13]); + } + /* + * Copy the sense information to the driver + */ + memcpy(sp->u_sense.cmd_sense, usallocal(usalp)->DomainSensePointer, sp->sense_len); + sp->sense_count = sp->sense_len; +} + + +static int +usalo_send(SCSI *usalp) +{ + linteger buffer_length; + linteger cdb_len; + scsi_$operation_id_t operation; + scsi_$wait_index_t wait_index; + scsi_$op_status_t op_status; + pinteger return_count; + status_$t status; + char *ascii_wait_status; + int i; + struct usal_cmd *sp = usalp->scmd; + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + + if (usalp->debug > 0) { + printf("Entered usalo_send, usalp=%p, sp=%p\n", usalp, sp); + printf("usalcmd dump:\n"); + printf(" addr=%p\n", sp->addr); + printf(" size=0x%x\n", sp->size); + printf(" flags=0x%x\n", sp->flags); + printf(" cdb_len=%d\n", sp->cdb_len); + printf(" sense_len=%d\n", sp->sense_len); + printf(" timeout=%d\n", sp->timeout); + printf(" kdebug=%d\n", sp->kdebug); + printf(" CDB:"); + for (i = 0; i < sp->cdb_len; i++) + printf(" %02x", sp->cdb.cmd_cdb[i]); + printf("\n"); + } + + /* + * Assume complete transfer, so residual count = 0 + */ + sp->resid = 0; + buffer_length = sp->size; + if (sp->addr) { + if (usalp->debug > 0) + printf(" wiring 0x%x bytes at 0x%x\n", buffer_length, sp->addr); + scsi_$wire(usallocal(usalp)->handle, sp->addr, buffer_length, &status); + if (status.all) { + /* + * Need better error handling + */ + printf("scsi_$wire failed, 0x%08x\n", status.all); + } + } + cdb_len = sp->cdb_len; + scsi_$do_command_2(usallocal(usalp)->handle, /* device handle*/ + *(scsi_$cdb_t *) &(sp->cdb.cmd_cdb[0]), /* SCSI CDB */ + cdb_len, /* CDB len */ + sp->addr, /* DMA buf */ + buffer_length, /* DMA len */ + (sp->flags & SCG_RECV_DATA) ? scsi_read : scsi_write, + &operation, /* OP ID */ + &status); /* Status ret */ + + if (status.all) { + /* + * Need better error handling + */ + printf("scsi_$do_command failed, 0x%08x\n", status.all); + sp->error = SCG_FATAL; + sp->ux_errno = EIO; + return (0); + } else if (usalp->debug > 0) { + printf("Command submitted, operation=0x%x\n", operation); + } + wait_index = scsi_$wait(usallocal(usalp)->handle, /* device handle*/ + sp->timeout * 1000, /* timeout */ + 0, /* async enable */ + operation, /* OP ID */ + 1, /* max count */ + &op_status, /* status list */ + &return_count, /* count ret */ + &status); /* Status ret */ + if (status.all) { + /* + * Need better error handling + */ + printf("scsi_$wait failed, 0x%08x\n", status.all); + sp->error = SCG_FATAL; + sp->ux_errno = EIO; + return (0); + } else { + if (usalp->debug > 0) { + printf("wait_index=%d, return_count=%d, op_status: op=0x%x, cmd_status=0x%x, op_status=0x%x\n", + wait_index, return_count, op_status.op, op_status.cmd_status, op_status.op_status); + } + switch (wait_index) { + + case scsi_device_advance: + ascii_wait_status = "scsi_device_advance"; + break; + case scsi_timeout: + ascii_wait_status = "scsi_timeout"; + break; + case scsi_async_fault: + ascii_wait_status = "scsi_async_fault"; + break; + default: + ascii_wait_status = "unknown"; + break; + } + /* + * See if the scsi_$wait terminated "abnormally" + */ + if (wait_index != scsi_device_advance) { + printf("scsi_$wait terminated abnormally, status='%s'\n", ascii_wait_status); + sp->error = SCG_FATAL; + sp->ux_errno = EIO; + return (0); + } + /* + * Normal termination, what's the scoop? + */ + assert(return_count == 1); + switch (op_status.cmd_status.all) { + + case status_$ok: + switch (op_status.op_status) { + + case scsi_good_status: + sp->error = SCG_NO_ERROR; + sp->ux_errno = 0; + break; + case scsi_busy: + sp->error = SCG_NO_ERROR; + sp->ux_errno = 0; + break; + case scsi_check_condition: + if (usalp->debug > 0) + printf("SCSI ERROR - CheckCondition\n"); + scsi_do_sense(usalp, sp); + /* + * If this was a media error, then call it retryable, + * instead of no error + */ + if ((((u_char *) usallocal(usalp)->DomainSensePointer)[0] == 0xf0) && + (((u_char *) usallocal(usalp)->DomainSensePointer)[2] == 0x03)) { + if (usalp->debug > 0) + printf(" (retryable)\n"); + sp->error = SCG_RETRYABLE; + sp->ux_errno = EIO; + } else { + /* printf(" (no error)\n"); */ + sp->error = SCG_NO_ERROR; + sp->ux_errno = 0; + } + break; + default: + /* + * I fault out in this case because I want to know + * about this error, and this guarantees that it will + * get attention. + */ + printf("Unhandled Domain/OS op_status error: status=%08x\n", + op_status.op_status); + exit(EXIT_FAILURE); + } + break; + /* + * Handle recognized error conditions by copying the error + * code over + */ + case scsi_$operation_timeout: + printf("SCSI ERROR - Timeout\n"); + scsi_do_sense(usalp, sp); + sp->error = SCG_TIMEOUT; + sp->ux_errno = EIO; + break; + case scsi_$dma_underrun: + /* + * This condition seems to occur occasionaly. I no longer + * complain because it doesn't seem to matter. + */ + if (usalp->debug > 0) + printf("SCSI ERROR - Underrun\n"); + scsi_do_sense(usalp, sp); + sp->resid = sp->size; /* We don't have the right number */ + sp->error = SCG_RETRYABLE; + sp->ux_errno = EIO; + break; + case scsi_$hdwr_failure: /* received when both scanners were active */ + printf("SCSI ERROR - Hardware Failure\n"); + scsi_do_sense(usalp, sp); + sp->error = SCG_RETRYABLE; + sp->ux_errno = EIO; + break; + default: + printf("\nUnhandled Domain/OS cmd_status error: status=%08x\n", op_status.cmd_status.all); + error_$print(op_status.cmd_status); + exit(EXIT_FAILURE); + } + } + if (sp->addr) { + if (usalp->debug > 0) + printf(" unwiring buffer\n"); + scsi_$unwire(usallocal(usalp)->handle, sp->addr, buffer_length, sp->flags & SCG_RECV_DATA, &status); + if (status.all) { + /* + * Need better error handling + */ + printf("scsi_$unwire failed, 0x%08x\n", status.all); + sp->error = SCG_FATAL; + sp->ux_errno = EIO; + return (0); + } + } + return (0); +} diff --git a/libusal/scsi-beos.c b/libusal/scsi-beos.c new file mode 100644 index 0000000..78b649e --- /dev/null +++ b/libusal/scsi-beos.c @@ -0,0 +1,414 @@ +/* + * 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-beos.c 1.23 06/02/05 Copyright 1998 J. Schilling */ +/* + * Interface for the BeOS user-land raw SCSI implementation. + * + * This is a hack, that tries to emulate the functionality + * of the usal driver. + * + * First version done by swetland@be.com + * + * 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. + * + * Copyright (c) 1998 J. Schilling + */ +/* + * 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. + */ + + +/* + * 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-beos.c-1.23"; /* The version for this transport*/ + +/* + * There are also defines for: + * B_BEOS_VERSION_4 + * B_BEOS_VERSION_4_5 + * + * in BeOS 5 + */ +#ifndef B_BEOS_VERSION_5 +/* + * New BeOS seems to include <be/kernel/OS.h> from device/scsi.h + */ + +/* nasty hack to avoid broken def of bool in SupportDefs.h */ +#define _SUPPORT_DEFS_H + +#ifndef _SYS_TYPES_H +typedef unsigned long ulong; +typedef unsigned int uint; +typedef unsigned short ushort; +#endif /* _SYS_TYPES_H */ + +#include <BeBuild.h> +#include <sys/types.h> +#include <Errors.h> + + +/*-------------------------------------------------------------*/ +/*----- Shorthand type formats --------------------------------*/ + +typedef signed char int8; +typedef unsigned char uint8; +typedef volatile signed char vint8; +typedef volatile unsigned char vuint8; + +typedef short int16; +typedef unsigned short uint16; +typedef volatile short vint16; +typedef volatile unsigned short vuint16; + +typedef long int32; +typedef unsigned long uint32; +typedef volatile long vint32; +typedef volatile unsigned long vuint32; + +typedef long long int64; +typedef unsigned long long uint64; +typedef volatile long long vint64; +typedef volatile unsigned long long vuint64; + +typedef volatile long vlong; +typedef volatile int vint; +typedef volatile short vshort; +typedef volatile char vchar; + +typedef volatile unsigned long vulong; +typedef volatile unsigned int vuint; +typedef volatile unsigned short vushort; +typedef volatile unsigned char vuchar; + +typedef unsigned char uchar; +typedef unsigned short unichar; + + + +/*-------------------------------------------------------------*/ +/*----- Descriptive formats -----------------------------------*/ +typedef int32 status_t; +typedef int64 bigtime_t; +typedef uint32 type_code; +typedef uint32 perform_code; + +/* end nasty hack */ + +#endif /* ! B_BEOS_VERSION_5 */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <usal/usalio.h> + +/* this is really really dumb (tm) */ +/*#undef sense*/ +/*#undef scb*/ +#include <device/scsi.h> + +#undef bool +#include <drivers/CAM.h> + +struct _fdmap_ { + struct _fdmap_ *next; + int bus; + int targ; + int lun; + int fd; +}; + +/* + * 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, "CAM", "Generic transport independent SCSI (BeOS CAM variant)", + "", "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); +#ifdef nonono + int tlun = usal_lun(usalp); +#endif + +#ifdef nonono + 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); + } +#endif + + 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); + } + return (1); +} + +static int +usalo_close(SCSI *usalp) +{ + struct _fdmap_ *f; + struct _fdmap_ *fnext; + + for (f = (struct _fdmap_ *)usalp->local; f; f = fnext) { + usalp->local = 0; + fnext = f->next; + close(f->fd); + free(f); + } + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + return (128*1024); + return (256*1024); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = malloc((size_t)(amt)); + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + usalp->bufbase = NULL; +} + +static BOOL +usalo_havebus(SCSI *usalp, int busno) +{ + struct stat sb; + char buf[128]; + + if (busno < 8) + snprintf(buf, sizeof (buf), "/dev/bus/scsi/%d", busno); + else + snprintf(buf, sizeof (buf), "/dev/disk/ide/atapi/%d", busno-8); + if (stat(buf, &sb)) + return (FALSE); + return (TRUE); +} + +static int +usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun) +{ + struct _fdmap_ *f; + char buf[128]; + int fd; + + for (f = (struct _fdmap_ *)usalp->local; f; f = f->next) { + if (f->bus == busno && f->targ == tgt && f->lun == tlun) + return (f->fd); + } + if (busno < 8) { + snprintf(buf, sizeof (buf), + "/dev/bus/scsi/%d/%d/%d/raw", + busno, tgt, tlun); + } else { + char *tgtstr = (tgt == 0) ? "master" : (tgt == 1) ? "slave" : "dummy"; + snprintf(buf, sizeof (buf), + "/dev/disk/ide/atapi/%d/%s/%d/raw", + busno-8, tgtstr, tlun); + } + fd = open(buf, 0); + + if (fd >= 0) { + f = (struct _fdmap_ *) malloc(sizeof (struct _fdmap_)); + f->bus = busno; + f->targ = tgt; + f->lun = tlun; + f->fd = fd; + f->next = (struct _fdmap_ *)usalp->local; + usalp->local = f; + } + return (fd); +} + +static int +usalo_initiator_id(SCSI *usalp) +{ + return (-1); +} + +static int +usalo_isatapi(SCSI *usalp) +{ + /* + * XXX Should check for ATAPI + */ + return (-1); +} + +static int +usalo_reset(SCSI *usalp, int what) +{ + errno = EINVAL; + return (-1); +} + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + int e; + int scsi_error; + int cam_error; + raw_device_command rdc; + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + + memcpy(rdc.command, &(sp->cdb), 12); + rdc.command_length = sp->cdb_len; + rdc.data = sp->addr; + rdc.data_length = sp->size; + rdc.sense_data_length = sp->sense_len; + rdc.sense_data = sp->u_sense.cmd_sense; + rdc.flags = sp->flags & SCG_RECV_DATA ? B_RAW_DEVICE_DATA_IN : 0; + if (sp->size > 0) + rdc.flags |= B_RAW_DEVICE_REPORT_RESIDUAL; + rdc.timeout = sp->timeout * 1000000; + + sp->error = SCG_NO_ERROR; + sp->sense_count = 0; + sp->u_scb.cmd_scb[0] = 0; + sp->resid = 0; + + if (usalp->debug > 0) { + fprintf(stderr, "SEND(%d): cmd %02x, cdblen = %d, datalen = %ld, senselen = %ld\n", + usalp->fd, rdc.command[0], rdc.command_length, + rdc.data_length, rdc.sense_data_length); + } + e = ioctl(usalp->fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof (rdc)); + if (usalp->debug > 0) { + fprintf(stderr, "SEND(%d): -> %d CAM Status %02X SCSI status %02X\n", e, rdc.cam_status, rdc.scsi_status); + } + sp->ux_errno = 0; +#ifdef DEBUG + fprintf(stderr, "err %d errno %x CAM %X SL %d DL %d/%d FL %X\n", + e, geterrno(), rdc.cam_status, + rdc.sense_data_length, rdc.data_length, sp->size, rdc.flags); +#endif + if (!e) { + cam_error = rdc.cam_status; + scsi_error = rdc.scsi_status; + sp->u_scb.cmd_scb[0] = scsi_error; + if (sp->size > 0) + sp->resid = sp->size - rdc.data_length; + + switch (cam_error & CAM_STATUS_MASK) { + + case CAM_REQ_CMP: + sp->error = SCG_NO_ERROR; + break; + + case CAM_REQ_CMP_ERR: + sp->sense_count = sp->sense_len; /* XXX */ + sp->error = SCG_NO_ERROR; + sp->ux_errno = EIO; + break; + + case CAM_CMD_TIMEOUT: + sp->error = SCG_TIMEOUT; + sp->ux_errno = EIO; + + case CAM_SEL_TIMEOUT: + sp->error = SCG_FATAL; + sp->ux_errno = EIO; + break; + + default: + sp->error = SCG_RETRYABLE; + sp->ux_errno = EIO; + } + } else { + sp->error = SCG_FATAL; + sp->ux_errno = geterrno(); + sp->resid = sp->size; + } + return (0); +} diff --git a/libusal/scsi-bsd-os.c b/libusal/scsi-bsd-os.c new file mode 100644 index 0000000..5719505 --- /dev/null +++ b/libusal/scsi-bsd-os.c @@ -0,0 +1,443 @@ +/* + * 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-bsd-os.c 1.28 04/01/15 Copyright 1997 J. Schilling */ +/* + * Interface for the BSD/OS user-land raw SCSI implementation. + * + * This is a hack, that tries to emulate the functionality + * of the usal driver. + * + * 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. + * + * Copyright (c) 1997 J. Schilling + */ +/* + * 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 scsi_sense bsdi_scsi_sense +#define scsi_inquiry bsdi_scsi_inquiry + +/* + * Must use -I/sys... + * The next two files are in /sys/dev/scsi + */ +#include <dev/scsi/scsi.h> +#include <dev/scsi/scsi_ioctl.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-bsd-os.c-1.28"; /* The version for this transport*/ + +#define MAX_SCG 16 /* Max # of SCSI controllers */ +#define MAX_TGT 16 +#define MAX_LUN 8 + +struct usal_local { + short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN]; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +#include <machine/param.h> + +#define MAX_DMA_BSDI MAXPHYS /* More makes problems */ + + +static BOOL usal_setup(SCSI *usalp, int f, int busno, int tgt, int tlun); + +/* + * 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, "SCSIRAWCDB", "Generic SCSI for devices known by BSDi", + "", "devname:@,lun", "/dev/rsr0a:@,0", FALSE, TRUE); + 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); + register int f; + register int b; + register int t; + register int l; + register int nopen = 0; + char devname[64]; + + 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 (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } + + if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) + goto openbydev; + + if (busno >= 0 && tgt >= 0 && tlun >= 0) { + + snprintf(devname, sizeof (devname), + "/dev/su%d-%d-%d", busno, tgt, tlun); + f = open(devname, O_RDWR|O_NONBLOCK); + if (f < 0) { + goto openbydev; + } + usallocal(usalp)->usalfiles[busno][tgt][tlun] = f; + return (1); + + } else for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + snprintf(devname, sizeof (devname), + "/dev/su%d-%d-%d", b, t, l); + f = open(devname, O_RDWR|O_NONBLOCK); +/* fprintf(stderr, "open (%s) = %d\n", devname, f);*/ + + if (f < 0) { + if (errno != ENOENT && + errno != ENXIO && + errno != ENODEV) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", + devname); + return (0); + } + } else { + if (usal_setup(usalp, f, b, t, l)) + nopen++; + } + } + } + } + /* + * Could not open /dev/su-* or got dev=devname:b,l,l / dev=devname:@,l + * We do the apropriate tests and try our best. + */ +openbydev: + if (nopen == 0) { + if (device == NULL || device[0] == '\0') + return (0); + f = open(device, O_RDWR|O_NONBLOCK); + if (f < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", + device); + return (0); + } + if (tlun == -2) { /* If 'lun' is not known, we reject */ + close(f); + errno = EINVAL; + return (0); + } + busno = 0; /* use fake number, we cannot get it */ + tgt = 0; /* use fake number, we cannot get it */ + usal_settarget(usalp, busno, tgt, tlun); + /* 'lun' has been specified on command line */ + if (usal_setup(usalp, f, busno, tgt, tlun)) + nopen++; + } + return (nopen); +} + +static int +usalo_close(SCSI *usalp) +{ + register int f; + register int b; + register int t; + register int l; + + if (usalp->local == NULL) + return (-1); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + f = usallocal(usalp)->usalfiles[b][t][l]; + if (f >= 0) + close(f); + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } + return (0); +} + +static BOOL +usal_setup(SCSI *usalp, int f, int busno, int tgt, int tlun) +{ + int Bus; + int Target; + int Lun; + BOOL onetarget = FALSE; + + if (usal_scsibus(usalp) >= 0 && usal_target(usalp) >= 0 && usal_lun(usalp) >= 0) + onetarget = TRUE; + + /* + * Unfortunately there is no way to get the right values from kernel. + */ + Bus = busno; + Target = tgt; + Lun = tlun; + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Bus: %d Target: %d Lun: %d\n", Bus, Target, Lun); + } + + if (Bus >= MAX_SCG || Target >= MAX_TGT || Lun >= MAX_LUN) { + close(f); + return (FALSE); + } + + if (usallocal(usalp)->usalfiles[Bus][Target][Lun] == (short)-1) + usallocal(usalp)->usalfiles[Bus][Target][Lun] = (short)f; + + if (onetarget) { + if (Bus == busno && Target == tgt && Lun == tlun) { + return (TRUE); + } else { + usallocal(usalp)->usalfiles[Bus][Target][Lun] = (short)-1; + close(f); + } + } + return (FALSE); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + long maxdma = MAX_DMA_BSDI; + + return (maxdma); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = malloc((size_t)(amt)); + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + 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); + + if (usalp->local == NULL) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if (usallocal(usalp)->usalfiles[busno][t][l] >= 0) + return (TRUE); + } + return (FALSE); +} + +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); + + if (usalp->local == NULL) + return (-1); + + return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]); +} + +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) +{ + /* + * Cannot reset on BSD/OS + */ + errno = EINVAL; + return (-1); +} + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + scsi_user_cdb_t suc; + int ret = 0; + +/* fprintf((FILE *)usalp->errfile, "f: %d\n", f);*/ + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + + /* Zero the structure... */ + fillbytes(&suc, sizeof (suc), '\0'); + + /* Read or write? */ + if (sp->flags & SCG_RECV_DATA) { + suc.suc_flags |= SUC_READ; + } else if (sp->size > 0) { + suc.suc_flags |= SUC_WRITE; + } + + suc.suc_timeout = sp->timeout; + + suc.suc_cdblen = sp->cdb_len; + movebytes(sp->cdb.cmd_cdb, suc.suc_cdb, suc.suc_cdblen); + + suc.suc_datalen = sp->size; + suc.suc_data = sp->addr; + + if (ioctl(usalp->fd, SCSIRAWCDB, &suc) < 0) { + ret = -1; + sp->ux_errno = geterrno(); + if (sp->ux_errno != ENOTTY) + ret = 0; + } else { + sp->ux_errno = 0; + if (suc.suc_sus.sus_status != STS_GOOD) + sp->ux_errno = EIO; + } + fillbytes(&sp->scb, sizeof (sp->scb), '\0'); + fillbytes(&sp->u_sense.cmd_sense, sizeof (sp->u_sense.cmd_sense), '\0'); +#if 0 + /* + * Unfortunalety, BSD/OS has no idea of DMA residual count. + */ + sp->resid = req.datalen - req.datalen_used; + sp->sense_count = req.senselen_used; +#else + sp->resid = 0; + sp->sense_count = sizeof (suc.suc_sus.sus_sense); +#endif + if (sp->sense_count > SCG_MAX_SENSE) + sp->sense_count = SCG_MAX_SENSE; + movebytes(suc.suc_sus.sus_sense, sp->u_sense.cmd_sense, sp->sense_count); + sp->u_scb.cmd_scb[0] = suc.suc_sus.sus_status; + + switch (suc.suc_sus.sus_status) { + + case STS_GOOD: + sp->error = SCG_NO_ERROR; break; + case STS_CMD_TERMINATED:sp->error = SCG_TIMEOUT; break; + case STS_BUSY: sp->error = SCG_RETRYABLE; break; + case STS_CHECKCOND: sp->error = SCG_RETRYABLE; break; + case STS_QUEUE_FULL: sp->error = SCG_RETRYABLE; break; + default: sp->error = SCG_FATAL; break; + } + + return (ret); +} + +#define sense u_sense.Sense + +#undef scsi_sense +#undef scsi_inquiry diff --git a/libusal/scsi-bsd.c b/libusal/scsi-bsd.c new file mode 100644 index 0000000..6e6c240 --- /dev/null +++ b/libusal/scsi-bsd.c @@ -0,0 +1,992 @@ +/* + * 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-bsd.c 1.42 04/01/15 Copyright 1997 J. Schilling */ +/* + * Interface for the NetBSD/FreeBSD/OpenBSD generic SCSI implementation. + * + * This is a hack, that tries to emulate the functionality + * of the usal driver. + * The SCSI tranport of the generic *BSD implementation is very + * similar to the SCSI command transport of the + * 6 years older usal driver. + * + * 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. + * + * Copyright (c) 1997 J. Schilling + */ +/* + * 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. + */ + +#ifndef HAVE_CAMLIB_H + +#undef sense +#include <sys/scsiio.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-bsd.c-1.42"; /* The version for this transport*/ + +#define MAX_SCG 16 /* Max # of SCSI controllers */ +#define MAX_TGT 16 +#define MAX_LUN 8 + +struct usal_local { + short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN]; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +/*#define MAX_DMA_BSD (32*1024)*/ +#define MAX_DMA_BSD (60*1024) /* More seems to make problems */ + +#if defined(__NetBSD__) && defined(TYPE_ATAPI) +/* + * NetBSD 1.3 has a merged SCSI/ATAPI system, so this structure + * is slightly different. + */ +#define MAYBE_ATAPI +#define SADDR_ISSCSI(a) ((a).type == TYPE_SCSI) + +#define SADDR_BUS(a) (SADDR_ISSCSI(a)?(a).addr.scsi.scbus:(MAX_SCG-1)) +#define SADDR_TARGET(a) (SADDR_ISSCSI(a)?(a).addr.scsi.target:(a).addr.atapi.atbus*2+(a).addr.atapi.drive) +#define SADDR_LUN(a) (SADDR_ISSCSI(a)?(a).addr.scsi.lun:0) +#else + +#if defined(__OpenBSD__) && defined(TYPE_ATAPI) +#define SADDR_ISSCSI(a) ((a).type == TYPE_SCSI) +#else +#define SADDR_ISSCSI(a) (1) +#endif + +#define SADDR_BUS(a) (a).scbus +#define SADDR_TARGET(a) (a).target +#define SADDR_LUN(a) (a).lun +#endif /* __NetBSD__ && TYPE_ATAPI */ + +static BOOL usal_setup(SCSI *usalp, int f, int busno, int tgt, int tlun); + +/* + * 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, "SCIOCCOMMAND", "SCSI for devices known by *BSD", + "", "device or bus,target,lun", "/dev/rcd0a:@ or 1,2,0", FALSE, TRUE); + 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); + register int f; + register int b; + register int t; + register int l; + register int nopen = 0; + char devname[64]; + + 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 (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } + + if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) + goto openbydev; + + if (busno >= 0 && tgt >= 0 && tlun >= 0) { + + snprintf(devname, sizeof (devname), + "/dev/su%d-%d-%d", busno, tgt, tlun); + f = open(devname, O_RDWR); + if (f < 0) { + goto openbydev; + } + usallocal(usalp)->usalfiles[busno][tgt][tlun] = f; + return (1); + + } else for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + snprintf(devname, sizeof (devname), + "/dev/su%d-%d-%d", b, t, l); + f = open(devname, O_RDWR); +/* fprintf(stderr, "open (%s) = %d\n", devname, f);*/ + + if (f < 0) { + if (errno != ENOENT && + errno != ENXIO && + errno != ENODEV) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", + devname); + return (0); + } + } else { + if (usal_setup(usalp, f, b, t, l)) + nopen++; + } + } + } + } + /* + * Could not open /dev/su-* or got dev=devname:b,l,l / dev=devname:@,l + * We do the apropriate tests and try our best. + */ +openbydev: + if (nopen == 0) { + struct scsi_addr saddr; + + if (device == NULL || device[0] == '\0') + return (0); + f = open(device, O_RDWR); + if (f < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", + device); + return (0); + } + if (tgt == -2) { + if (ioctl(f, SCIOCIDENTIFY, &saddr) < 0) { + close(f); + errno = EINVAL; + return (0); + } + busno = SADDR_BUS(saddr); + tgt = SADDR_TARGET(saddr); + if ((tlun >= 0) && (tlun != SADDR_LUN(saddr))) { + close(f); + errno = EINVAL; + return (0); + } + tlun = SADDR_LUN(saddr); + usal_settarget(usalp, busno, tgt, tlun); + } + if (usal_setup(usalp, f, busno, tgt, tlun)) + nopen++; + } + return (nopen); +} + +static int +usalo_close(SCSI *usalp) +{ + register int f; + register int b; + register int t; + register int l; + + if (usalp->local == NULL) + return (-1); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + f = usallocal(usalp)->usalfiles[b][t][l]; + if (f >= 0) + close(f); + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } + return (0); +} + +static BOOL +usal_setup(SCSI *usalp, int f, int busno, int tgt, int tlun) +{ + struct scsi_addr saddr; + int Bus; + int Target; + int Lun; + BOOL onetarget = FALSE; + + if (usal_scsibus(usalp) >= 0 && usal_target(usalp) >= 0 && usal_lun(usalp) >= 0) + onetarget = TRUE; + + if (ioctl(f, SCIOCIDENTIFY, &saddr) < 0) { + errmsg("Cannot get SCSI addr.\n"); + close(f); + return (FALSE); + } + Bus = SADDR_BUS(saddr); + Target = SADDR_TARGET(saddr); + Lun = SADDR_LUN(saddr); + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Bus: %d Target: %d Lun: %d\n", Bus, Target, Lun); + } + + if (Bus >= MAX_SCG || Target >= MAX_TGT || Lun >= MAX_LUN) { + close(f); + return (FALSE); + } + + if (usallocal(usalp)->usalfiles[Bus][Target][Lun] == (short)-1) + usallocal(usalp)->usalfiles[Bus][Target][Lun] = (short)f; + + if (onetarget) { + if (Bus == busno && Target == tgt && Lun == tlun) { + return (TRUE); + } else { + usallocal(usalp)->usalfiles[Bus][Target][Lun] = (short)-1; + close(f); + } + } + return (FALSE); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + long maxdma = MAX_DMA_BSD; + + return (maxdma); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = valloc((size_t)(amt)); + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + 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); + + if (usalp->local == NULL) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if (usallocal(usalp)->usalfiles[busno][t][l] >= 0) + return (TRUE); + } + return (FALSE); +} + +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); + + if (usalp->local == NULL) + return (-1); + + return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]); +} + +static int +usalo_initiator_id(SCSI *usalp) +{ + return (-1); +} + +static int +usalo_isatapi(SCSI *usalp) +{ +#ifdef MAYBE_ATAPI + struct scsi_addr saddr; + + if (ioctl(usalp->fd, SCIOCIDENTIFY, &saddr) < 0) + return (-1); + + if (!SADDR_ISSCSI(saddr)) + return (TRUE); +#endif + return (FALSE); +} + +static int +usalo_reset(SCSI *usalp, int what) +{ + if (what == SCG_RESET_NOP) + return (0); + if (what != SCG_RESET_BUS) { + errno = EINVAL; + return (-1); + } + /* + * XXX Does this reset TGT or BUS ??? + */ + return (ioctl(usalp->fd, SCIOCRESET, 0)); +} + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + scsireq_t req; + register long *lp1; + register long *lp2; + int ret = 0; + +/* fprintf((FILE *)usalp->errfile, "fd: %d\n", usalp->fd);*/ + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + req.flags = SCCMD_ESCAPE; /* We set the SCSI cmd len */ + if (sp->flags & SCG_RECV_DATA) + req.flags |= SCCMD_READ; + else if (sp->size > 0) + req.flags |= SCCMD_WRITE; + + req.timeout = sp->timeout * 1000; + lp1 = (long *)sp->cdb.cmd_cdb; + lp2 = (long *)req.cmd; + *lp2++ = *lp1++; + *lp2++ = *lp1++; + *lp2++ = *lp1++; + *lp2++ = *lp1++; + req.cmdlen = sp->cdb_len; + req.databuf = sp->addr; + req.datalen = sp->size; + req.datalen_used = 0; + fillbytes(req.sense, sizeof (req.sense), '\0'); + if (sp->sense_len > sizeof (req.sense)) + req.senselen = sizeof (req.sense); + else if (sp->sense_len < 0) + req.senselen = 0; + else + req.senselen = sp->sense_len; + req.senselen_used = 0; + req.status = 0; + req.retsts = 0; + req.error = 0; + + if (ioctl(usalp->fd, SCIOCCOMMAND, (void *)&req) < 0) { + ret = -1; + sp->ux_errno = geterrno(); + if (sp->ux_errno != ENOTTY) + ret = 0; + } else { + sp->ux_errno = 0; + if (req.retsts != SCCMD_OK) + sp->ux_errno = EIO; + } + fillbytes(&sp->scb, sizeof (sp->scb), '\0'); + fillbytes(&sp->u_sense.cmd_sense, sizeof (sp->u_sense.cmd_sense), '\0'); + sp->resid = req.datalen - req.datalen_used; + sp->sense_count = req.senselen_used; + if (sp->sense_count > SCG_MAX_SENSE) + sp->sense_count = SCG_MAX_SENSE; + movebytes(req.sense, sp->u_sense.cmd_sense, sp->sense_count); + sp->u_scb.cmd_scb[0] = req.status; + + switch (req.retsts) { + + case SCCMD_OK: +#ifdef BSD_SCSI_SENSE_BUG + sp->u_scb.cmd_scb[0] = 0; + sp->ux_errno = 0; +#endif + sp->error = SCG_NO_ERROR; break; + case SCCMD_TIMEOUT: sp->error = SCG_TIMEOUT; break; + default: + case SCCMD_BUSY: sp->error = SCG_RETRYABLE; break; + case SCCMD_SENSE: sp->error = SCG_RETRYABLE; break; + case SCCMD_UNKNOWN: sp->error = SCG_FATAL; break; + } + + return (ret); +} +#define sense u_sense.Sense + +#else /* BSD_CAM */ +/* + * Interface for the FreeBSD CAM passthrough device. + * + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * Copyright (c) 1998 Kenneth D. Merry <ken@kdm.org> + * Copyright (c) 1998 Joerg Schilling <schilling@fokus.gmd.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#undef sense +#define scsi_sense CAM_scsi_sense +#define scsi_inquiry CAM_scsi_inquiry +#include <sys/param.h> +#include <cam/cam.h> +#include <cam/cam_ccb.h> +#include <cam/scsi/scsi_message.h> +#include <cam/scsi/scsi_pass.h> +#include <camlib.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-bsd.c-1.42"; /* The version for this transport*/ + +#define CAM_MAXDEVS 128 +struct usal_local { + struct cam_device *cam_devices[CAM_MAXDEVS + 1]; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +/* + * 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, "CAM", "Generic transport independent SCSI (Common Access Method)", + "", "bus,target,lun", "1,2,0", TRUE, FALSE); + return (0); +} + +/* + * Build a list of everything we can find. + */ +static int +usalo_open(SCSI *usalp, char *device) +{ + int busno = usal_scsibus(usalp); + int tgt = usal_target(usalp); + int tlun = usal_lun(usalp); + char name[16]; + int unit; + int nopen = 0; + union ccb ccb; + int bufsize; + struct periph_match_pattern *match_pat; + int fd; + + 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); + + for (unit = 0; unit <= CAM_MAXDEVS; unit++) { + usallocal(usalp)->cam_devices[unit] = (struct cam_device *)-1; + } + } + + + /* + * If we're not scanning the bus, just open one device. + */ + if (busno >= 0 && tgt >= 0 && tlun >= 0) { + usallocal(usalp)->cam_devices[0] = cam_open_btl(busno, tgt, tlun, O_RDWR, NULL); + if (usallocal(usalp)->cam_devices[0] == NULL) + return (-1); + nopen++; + return (nopen); + } + + /* + * First open the transport layer device. There's no point in the + * rest of this if we can't open it. + */ + + if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Open of %s failed", XPT_DEVICE); + return (-1); + } + fillbytes(&ccb, sizeof (union ccb), '\0'); + + /* + * Get a list of up to CAM_MAXDEVS passthrough devices in the + * system. + */ + ccb.ccb_h.func_code = XPT_DEV_MATCH; + + /* + * Setup the result buffer. + */ + bufsize = sizeof (struct dev_match_result) * CAM_MAXDEVS; + ccb.cdm.match_buf_len = bufsize; + ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); + if (ccb.cdm.matches == NULL) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Couldn't malloc match buffer"); + close(fd); + return (-1); + } + ccb.cdm.num_matches = 0; + + /* + * Setup the pattern buffer. We're matching against all + * peripherals named "pass". + */ + ccb.cdm.num_patterns = 1; + ccb.cdm.pattern_buf_len = sizeof (struct dev_match_pattern); + ccb.cdm.patterns = (struct dev_match_pattern *)malloc( + sizeof (struct dev_match_pattern)); + if (ccb.cdm.patterns == NULL) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Couldn't malloc pattern buffer"); + close(fd); + free(ccb.cdm.matches); + return (-1); + } + ccb.cdm.patterns[0].type = DEV_MATCH_PERIPH; + match_pat = &ccb.cdm.patterns[0].pattern.periph_pattern; + snprintf(match_pat->periph_name, sizeof (match_pat->periph_name), + "pass"); + match_pat->flags = PERIPH_MATCH_NAME; + + if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "CAMIOCOMMAND ioctl failed"); + close(fd); + free(ccb.cdm.matches); + free(ccb.cdm.patterns); + return (-1); + } + + if ((ccb.ccb_h.status != CAM_REQ_CMP) || + ((ccb.cdm.status != CAM_DEV_MATCH_LAST) && + (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { +/* errmsgno(EX_BAD, "Got CAM error 0x%X, CDM error %d.\n",*/ + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Got CAM error 0x%X, CDM error %d", + ccb.ccb_h.status, ccb.cdm.status); + close(fd); + free(ccb.cdm.matches); + free(ccb.cdm.patterns); + return (-1); + } + + free(ccb.cdm.patterns); + close(fd); + + for (unit = 0; unit < MIN(CAM_MAXDEVS, ccb.cdm.num_matches); unit++) { + struct periph_match_result *periph_result; + + /* + * We shouldn't have anything other than peripheral + * matches in here. If we do, it means an error in the + * device matching code in the transport layer. + */ + if (ccb.cdm.matches[unit].type != DEV_MATCH_PERIPH) { +/* errmsgno(EX_BAD, "Kernel error! got periph match type %d!!\n",*/ + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Kernel error! got periph match type %d!!", + ccb.cdm.matches[unit].type); + free(ccb.cdm.matches); + return (-1); + } + periph_result = &ccb.cdm.matches[unit].result.periph_result; + + snprintf(name, sizeof (name), + "/dev/%s%d", periph_result->periph_name, + periph_result->unit_number); + + /* + * cam_open_pass() avoids all lookup and translation from + * "regular device name" to passthrough unit number and + * just opens the device in question as a passthrough device. + */ + usallocal(usalp)->cam_devices[unit] = cam_open_pass(name, O_RDWR, NULL); + + /* + * If we get back NULL from the open routine, it wasn't + * able to open the given passthrough device for one reason + * or another. + */ + if (usallocal(usalp)->cam_devices[unit] == NULL) { +#ifdef OLD + errmsgno(EX_BAD, "Error opening /dev/%s%d\n", + periph_result->periph_name, + periph_result->unit_number); + errmsgno(EX_BAD, "%s\n", cam_errbuf); +#endif + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Error opening /dev/%s%d Cam error '%s'", + periph_result->periph_name, + periph_result->unit_number, + cam_errbuf); + break; + } + nopen++; + } + + free(ccb.cdm.matches); + return (nopen); +} + +static int +usalo_close(SCSI *usalp) +{ + register int i; + + if (usalp->local == NULL) + return (-1); + + for (i = 0; i <= CAM_MAXDEVS; i++) { + if (usallocal(usalp)->cam_devices[i] != (struct cam_device *)-1) + cam_close_device(usallocal(usalp)->cam_devices[i]); + usallocal(usalp)->cam_devices[i] = (struct cam_device *)-1; + } + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ +#ifdef DFLTPHYS + return (DFLTPHYS); +#else + return (MAXPHYS); +#endif +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = valloc((size_t)(amt)); + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + usalp->bufbase = NULL; +} + +static BOOL +usalo_havebus(SCSI *usalp, int busno) +{ + int unit; + + if (usalp->local == NULL) + return (FALSE); + + /* + * There's a "cleaner" way to do this, using the matching code, but + * it would involve more code than this solution... + */ + for (unit = 0; usallocal(usalp)->cam_devices[unit] != (struct cam_device *)-1; unit++) { + if (usallocal(usalp)->cam_devices[unit] == NULL) + continue; + if (usallocal(usalp)->cam_devices[unit]->path_id == busno) + return (TRUE); + } + return (FALSE); +} + +static int +usalo_fileno(SCSI *usalp, int busno, int unit, int tlun) +{ + int i; + + if (usalp->local == NULL) + return (-1); + + for (i = 0; usallocal(usalp)->cam_devices[i] != (struct cam_device *)-1; i++) { + if (usallocal(usalp)->cam_devices[i] == NULL) + continue; + if ((usallocal(usalp)->cam_devices[i]->path_id == busno) && + (usallocal(usalp)->cam_devices[i]->target_id == unit) && + (usallocal(usalp)->cam_devices[i]->target_lun == tlun)) + return (i); + } + 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) +{ + /* XXX synchronous reset command - is this wise? */ + errno = EINVAL; + return (-1); +} + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + struct cam_device *dev; + union ccb ccb_space; + union ccb *ccb = &ccb_space; + int rv, result; + u_int32_t ccb_flags; + + if (usalp->fd < 0) { +#if 0 + fprintf((FILE *)usalp->errfile, + "attempt to reference invalid unit %d\n", usalp->fd); +#endif + sp->error = SCG_FATAL; + return (0); + } + + dev = usallocal(usalp)->cam_devices[usalp->fd]; + fillbytes(&ccb->ccb_h, sizeof (struct ccb_hdr), '\0'); + ccb->ccb_h.path_id = dev->path_id; + ccb->ccb_h.target_id = dev->target_id; + ccb->ccb_h.target_lun = dev->target_lun; + + /* Build the CCB */ + fillbytes(&(&ccb->ccb_h)[1], sizeof (struct ccb_scsiio), '\0'); + movebytes(sp->cdb.cmd_cdb, &ccb->csio.cdb_io.cdb_bytes, sp->cdb_len); + + /* + * Set the data direction flags. + */ + if (sp->size != 0) { + ccb_flags = (sp->flags & SCG_RECV_DATA) ? CAM_DIR_IN : + CAM_DIR_OUT; + } else { + ccb_flags = CAM_DIR_NONE; + } + + ccb_flags |= CAM_DEV_QFRZDIS; + + /* + * If you don't want to bother with sending tagged commands under CAM, + * we don't need to do anything to cdrecord. If you want to send + * tagged commands to those devices that support it, we'll need to set + * the tag action valid field like this in usalo_send(): + * + * ccb_flags |= CAM_DEV_QFRZDIS | CAM_TAG_ACTION_VALID; + */ + + cam_fill_csio(&ccb->csio, + /* retries */ 1, + /* cbfncp */ NULL, + /* flags */ ccb_flags, + /* tag_action */ MSG_SIMPLE_Q_TAG, + /* data_ptr */ (u_int8_t *)sp->addr, + /* dxfer_len */ sp->size, + /* sense_len */ SSD_FULL_SIZE, + /* cdb_len */ sp->cdb_len, + /* timeout */ sp->timeout * 1000); + + /* Run the command */ + errno = 0; + if ((rv = cam_send_ccb(dev, ccb)) == -1) { + return (rv); + } else { + /* + * Check for command status. Selection timeouts are fatal. + * For command timeouts, we pass back the appropriate + * error. If we completed successfully, there's (obviously) + * no error. We declare anything else "retryable". + */ + switch (ccb->ccb_h.status & CAM_STATUS_MASK) { + case CAM_SEL_TIMEOUT: + result = SCG_FATAL; + break; + case CAM_CMD_TIMEOUT: + result = SCG_TIMEOUT; + break; + case CAM_REQ_CMP: + result = SCG_NO_ERROR; + break; + default: + result = SCG_RETRYABLE; + break; + } + } + + sp->error = result; + if (result != SCG_NO_ERROR) + sp->ux_errno = EIO; + + /* Pass the result back up */ + fillbytes(&sp->scb, sizeof (sp->scb), '\0'); + fillbytes(&sp->u_sense.cmd_sense, sizeof (sp->u_sense.cmd_sense), '\0'); + sp->resid = ccb->csio.resid; + sp->sense_count = SSD_FULL_SIZE - ccb->csio.sense_resid; + + /* + * Determine how much room we have for sense data. + */ + if (sp->sense_count > SCG_MAX_SENSE) + sp->sense_count = SCG_MAX_SENSE; + + /* Copy the sense data out */ + movebytes(&ccb->csio.sense_data, &sp->u_sense.cmd_sense, sp->sense_count); + + sp->u_scb.cmd_scb[0] = ccb->csio.scsi_status; + + return (0); +} + +#undef scsi_sense +#undef scsi_inquiry +#define sense u_sense.Sense + +#endif /* BSD_CAM */ diff --git a/libusal/scsi-dos.c b/libusal/scsi-dos.c new file mode 100644 index 0000000..ecf36ce --- /dev/null +++ b/libusal/scsi-dos.c @@ -0,0 +1,562 @@ +/* + * 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-dos.c 1.11 03/12/10 Copyright 1998-2003 J. Schilling, 2003 Alex Kopylov reanimatolog@yandex.ru */ +/* + * Interface for the MS-DOS ASPI managers. + * You need ASPI manager installed in your config.sys: + * aspi*.sys for SCSI devices + * oakaspi.sys for ATAPI devices + * usbaspi.sys for USB devices + * + * Made from Win32 ASPI library template. + * + * 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. + * + * Copyright (c) 1998-2003 J. Schilling + * Copyright (c) 1999 A.L. Faber for the first implementation + * of this interface. + * Copyright (c) 2003 Alex Kopylov reanimatolog@yandex.ru + */ +/* + * 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. + */ + +#include <dos.h> +#include <dpmi.h> +#include <go32.h> +#include <usal/aspi-dos.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-dos.c-1.11"; /* The version for this transport*/ + +#define MAX_SCG 8 +#define MAX_TGT 8 +#define MAX_LUN 8 + +struct usal_local { + int dummy; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +#define MAX_DMA_DOS (63L*1024L) + +static BYTE busses = 1; +static DWORD SCSIMgrEntry = 0; +static int AspiLoaded = 0; + +static BOOL _callback_flag; +static _go32_dpmi_seginfo _callback_info; +static _go32_dpmi_registers _callback_regs; + +static BOOL SCSIMgrOpen(SCSI *); +static void SCSIMgrClose(void); +static int SCSIMgrSendSRB(SRB *, time_t); +static void SCSIMgrCallBack(_go32_dpmi_registers *regs); + +static char * +usalo_version(SCSI *usalp, int what) +{ + if (usalp != (SCSI *)0) { + switch (what) { + + case SCG_VERSION: + return (_usal_trans_version); + 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); + } + + /* + * Check if variables are within the range + */ + if (tgt >= 0 && tgt >= 0 && tlun >= 0) { + /* + * This is the non -scanbus case. + */ + ; + } else if (tgt != -1 || tgt != -1 || tlun != -1) { + errno = EINVAL; + return (-1); + } + + if (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + } + /* + * Try to open ASPI-Router + */ + if (!SCSIMgrOpen(usalp)) + return (-1); + + /* + * More than we have ... + */ + if (busno >= busses) { + SCSIMgrClose(); + return (-1); + } + + /* + * Install Exit Function which closes the ASPI-Router + */ + atexit(SCSIMgrClose); + + /* + * Success after all + */ + return (1); +} + +static int +usalo_close(SCSI *usalp) +{ + SCSIMgrClose(); + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + return (MAX_DMA_DOS); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = malloc((size_t)(amt)); + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + usalp->bufbase = NULL; +} + +static __SBOOL +usalo_havebus(SCSI *usalp, int busno) +{ + if (busno < 0 || busno >= busses) + return (FALSE); + + return (TRUE); +} + +static int +usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun) +{ + if (busno < 0 || busno >= busses || + 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 (-1); +} + +static int +usalo_reset(SCSI *usalp, int what) +{ + errno = EINVAL; + return (-1); +} + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + SRB Srb; + int dos_memory_data_seg; + int dos_memory_data_sel; + DWORD dos_memory_data_ptr; + + /* + * Check if ASPI library is loaded + */ + if (!SCSIMgrEntry) { + errmsgno(EX_BAD, "error in usalo_send: ASPI driver not loaded.\n"); + sp->error = SCG_FATAL; + return (-1); + } + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + + /* + * Initialize variables + */ + sp->error = SCG_NO_ERROR; + sp->sense_count = 0; + sp->u_scb.cmd_scb[0] = 0; + sp->resid = 0; + + memset(&Srb, 0, sizeof (Srb)); + + switch (sp->cdb_len) { + + case 6: + movebytes(&sp->cdb, &(Srb.Type.ExecSCSICmd.CmdLen._6.CDBByte), sp->cdb_len); + break; + case 10: + movebytes(&sp->cdb, &(Srb.Type.ExecSCSICmd.CmdLen._10.CDBByte), sp->cdb_len); + break; + case 12: + movebytes(&sp->cdb, &(Srb.Type.ExecSCSICmd.CmdLen._12.CDBByte), sp->cdb_len); + break; + default: + sp->error = SCG_FATAL; + sp->ux_errno = EINVAL; + fprintf((FILE *)usalp->errfile, + "Unsupported sp->cdb_len: %u. Fatal error in usalo_send, exiting...\n", sp->cdb_len); + return (-1); + } + + if ((dos_memory_data_seg = __dpmi_allocate_dos_memory((sp->size>>4)+1, &dos_memory_data_sel)) == -1) { + sp->error = SCG_FATAL; + return (-1); + } + dos_memory_data_ptr = dos_memory_data_seg<<16; + + _dosmemputb(sp->addr, sp->size, dos_memory_data_seg<<4); + + Srb.Cmd = SC_EXEC_SCSI_CMD; + Srb.HaId = usal_scsibus(usalp); + Srb.Type.ExecSCSICmd.Target = usal_target(usalp); + Srb.Type.ExecSCSICmd.Lun = usal_lun(usalp); + Srb.Type.ExecSCSICmd.BufLen = sp->size; + Srb.Type.ExecSCSICmd.BufPointer = (void *)dos_memory_data_ptr; + Srb.Type.ExecSCSICmd.CDBLen = sp->cdb_len; + if (sp->sense_len <= (SENSE_LEN+2)) + Srb.Type.ExecSCSICmd.SenseLen = sp->sense_len; + else + Srb.Type.ExecSCSICmd.SenseLen = (SENSE_LEN+2); + + /* + * Enable SCSIMgrCallBack() + */ + Srb.Flags |= SRB_POSTING; + Srb.Type.ExecSCSICmd.PostProc = (void *)(_callback_info.rm_offset|(_callback_info.rm_segment<<16)); + + /* + * Do we receive data from this ASPI command? + */ + if (sp->flags & SCG_RECV_DATA) { + + Srb.Flags |= SRB_DIR_IN; + } else { + /* + * Set direction to output + */ + if (sp->size > 0) { + Srb.Flags |= SRB_DIR_OUT; + } + } + + SCSIMgrSendSRB(&Srb, usalp->scmd->timeout); + Srb.Type.ExecSCSICmd.BufPointer = sp->addr; + _dosmemgetb(dos_memory_data_seg<<4, sp->size, sp->addr); + __dpmi_free_dos_memory(dos_memory_data_sel); + + if (Srb.Status == SS_PENDING) { /* Check if we got a timeout*/ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Timeout....\n"); + } + sp->error = SCG_TIMEOUT; + return (1); /* Return error */ + } + + /* + * Check ASPI command status + */ + if (Srb.Status != SS_COMP) { + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Error in usalo_send: Srb.Status is 0x%x\n", Srb.Status); + } + + switch (Srb.Status) { + + case SS_COMP: /* 0x01 SRB completed without error */ + sp->error = SCG_NO_ERROR; + sp->ux_errno = 0; + break; + + case SS_PENDING: /* 0x00 SRB being processed */ + case SS_ABORTED: /* 0x02 SRB aborted */ + case SS_ABORT_FAIL: /* 0x03 Unable to abort SRB */ + default: + sp->error = SCG_RETRYABLE; + sp->ux_errno = EIO; + break; + + case SS_ERR: /* 0x04 SRB completed with error */ + /* + * If the SCSI Status byte is != 0, we definitely could send + * the command to the target. We signal NO transport error. + */ + sp->error = SCG_NO_ERROR; + sp->ux_errno = EIO; + if (Srb.Type.ExecSCSICmd.TargStat) + break; + + case SS_INVALID_CMD: /* 0x80 Invalid ASPI command */ + case SS_INVALID_HA: /* 0x81 Invalid host adapter number */ + case SS_NO_DEVICE: /* 0x82 SCSI device not installed */ + sp->error = SCG_FATAL; + sp->ux_errno = EINVAL; + break; + } + + sp->sense_count = Srb.Type.ExecSCSICmd.SenseLen; + if (sp->sense_count > sp->sense_len) + sp->sense_count = sp->sense_len; + + memset(&sp->u_sense.Sense, 0x00, sizeof (sp->u_sense.Sense)); + + switch (sp->cdb_len) { + + case 6: + memcpy(&sp->u_sense.Sense, Srb.Type.ExecSCSICmd.CmdLen._6.SenseArea, sp->sense_count); + break; + case 10: + memcpy(&sp->u_sense.Sense, Srb.Type.ExecSCSICmd.CmdLen._10.SenseArea, sp->sense_count); + break; + case 12: + memcpy(&sp->u_sense.Sense, Srb.Type.ExecSCSICmd.CmdLen._12.SenseArea, sp->sense_count); + break; + } + sp->u_scb.cmd_scb[0] = Srb.Type.ExecSCSICmd.TargStat; + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Mapped to: error %d errno: %d\n", sp->error, sp->ux_errno); + } + return (1); + } + + return (0); +} + +static BOOL +SCSIMgrOpen(SCSI *usalp) +{ + int hSCSIMgr; + int dos_memory_seg; + int dos_memory_sel; + __dpmi_regs _regs; + SRB Srb; + + if (SCSIMgrEntry) { + AspiLoaded++; + return (TRUE); + } + + /* + * Open "SCSIMRG$" + */ + if (!_dos_open("SCSIMGR$", 0, &hSCSIMgr)) { + + /* Alloc 16 bytes DOS memory */ + if ((dos_memory_seg = __dpmi_allocate_dos_memory(1, &dos_memory_sel)) != -1) { + + /* Look for SCSIMgr entry point */ + memset(&_regs, 0, sizeof (_regs)); + _regs.x.ax = 0x4402; + _regs.x.bx = hSCSIMgr; + _regs.x.cx = 0x0004; + _regs.x.ds = dos_memory_seg; + _regs.x.dx = 0x0000; + if (!__dpmi_simulate_real_mode_interrupt(0x21, &_regs)) { + _dosmemgetb(dos_memory_seg<<4, 4, &SCSIMgrEntry); + } + + /* Free DOS memory */ + __dpmi_free_dos_memory(dos_memory_sel); + } + + /* Close "SCSIMRG$" */ + _dos_close(hSCSIMgr); + + /* Allocate real mode callback */ + _callback_info.pm_offset = (unsigned long)&SCSIMgrCallBack; + if (_go32_dpmi_allocate_real_mode_callback_retf(&_callback_info, &_callback_regs) == -1) { + fprintf((FILE *)usalp->errfile, "Cannot allocate callback address!\n"); + SCSIMgrEntry = 0; + } + } + + /* SCSIMgr entry point founded? */ + if (!SCSIMgrEntry) { + fprintf((FILE *)usalp->errfile, "Cannot open ASPI manager! Try to get one from http://bootcd.narod.ru/\n"); + return (FALSE); + } + + memset(&Srb, 0, sizeof (Srb)); + Srb.Cmd = SC_HA_INQUIRY; + + SCSIMgrSendSRB(&Srb, 10); + + if (usalp->debug) { + fprintf((FILE *)usalp->errfile, "Status : %ld\n", Srb.Status); + fprintf((FILE *)usalp->errfile, "hacount: %d\n", Srb.Type.HAInquiry.Count); + fprintf((FILE *)usalp->errfile, "SCSI id: %d\n", Srb.Type.HAInquiry.SCSI_ID); + fprintf((FILE *)usalp->errfile, "Manager: '%.16s'\n", Srb.Type.HAInquiry.ManagerId); + fprintf((FILE *)usalp->errfile, "Identif: '%.16s'\n", Srb.Type.HAInquiry.Identifier); + usal_prbytes("Unique:", Srb.Type.HAInquiry.Unique, 16); + } + + AspiLoaded++; + return (TRUE); +} + +static void +SCSIMgrClose() +{ + if (--AspiLoaded > 0) + return; + if (SCSIMgrEntry) { + _go32_dpmi_free_real_mode_callback(&_callback_info); + SCSIMgrEntry = 0; + } +} + +static int +SCSIMgrSendSRB(SRB *Srb, time_t timeout) +{ + int dos_memory_srb_seg; + int dos_memory_srb_sel; + DWORD dos_memory_srb_ptr; + struct timeval st; + struct timeval cr; + __dpmi_regs _regs; + + /* Alloc DOS memory */ + if ((dos_memory_srb_seg = __dpmi_allocate_dos_memory((sizeof (SRB) >> 4) + 1, &dos_memory_srb_sel)) == -1) { + Srb->Status = SS_NO_DEVICE; /* ??? fatal error */ + return (Srb->Status); + } + dos_memory_srb_ptr = dos_memory_srb_seg<<16; + + /* Copy SRB to DOS memory */ + _dosmemputb((void *)Srb, sizeof (SRB), dos_memory_srb_seg<<4); + + /* Reset callback flag */ + _callback_flag = 0; + + /* Call SCSIMgr */ + memset(&_regs, 0, sizeof (_regs)); + _regs.x.ip = SCSIMgrEntry & 0xffff; + _regs.x.cs = SCSIMgrEntry >> 16; + __dpmi_simulate_real_mode_procedure_retf_stack(&_regs, 2, &dos_memory_srb_ptr); + + /* Wait 'timeout' seconds for Srb->Status != SS_PENDING */ + gettimeofday(&st, NULL); + do { + _dosmemgetb(dos_memory_srb_seg << 4, sizeof (SRB), (void *)Srb); + gettimeofday(&cr, NULL); + } while ((Srb->Status == SS_PENDING) && (cr.tv_sec - st.tv_sec < timeout)); + + /* Free DOS memory */ + __dpmi_free_dos_memory(dos_memory_srb_sel); + + return (Srb->Status); +} + +static void +SCSIMgrCallBack(_go32_dpmi_registers *regs) +{ + _callback_flag = 1; +} diff --git a/libusal/scsi-hpux.c b/libusal/scsi-hpux.c new file mode 100644 index 0000000..f7eb553 --- /dev/null +++ b/libusal/scsi-hpux.c @@ -0,0 +1,363 @@ +/* + * 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-hpux.c 1.31 04/01/15 Copyright 1997 J. Schilling */ +/* + * Interface for the HP-UX generic SCSI implementation. + * + * 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. + * + * Copyright (c) 1997 J. Schilling + */ +/* + * 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 +#include <sys/scsi.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-hpux.c-1.31"; /* The version for this transport*/ + +#define MAX_SCG 16 /* Max # of SCSI controllers */ +#define MAX_TGT 16 +#define MAX_LUN 8 + +struct usal_local { + short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN]; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +#ifdef SCSI_MAXPHYS +# define MAX_DMA_HP SCSI_MAXPHYS +#else +# define MAX_DMA_HP (63*1024) /* Check if this is not too big */ +#endif + + +/* + * 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, "SIOC", "Generic 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); + register int f; + register int b; + register int t; + register int l; + register int nopen = 0; + char devname[64]; + + 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); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } + + if (busno >= 0 && tgt >= 0 && tlun >= 0) { + + snprintf(devname, sizeof (devname), + "/dev/rscsi/c%xt%xl%x", busno, tgt, tlun); + f = open(devname, O_RDWR); + if (f < 0) + return (-1); + usallocal(usalp)->usalfiles[busno][tgt][tlun] = f; + return (1); + } else { + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { +/* for (l = 0; l < MAX_LUN; l++) {*/ + for (l = 0; l < 1; l++) { + snprintf(devname, sizeof (devname), + "/dev/rscsi/c%xt%xl%x", b, t, l); +/*fprintf(stderr, "name: '%s'\n", devname);*/ + f = open(devname, O_RDWR); + if (f >= 0) { + usallocal(usalp)->usalfiles[b][t][l] = (short)f; + nopen++; + } else if (usalp->debug > 0) { + errmsg("open '%s'\n", devname); + } + } + } + } + } + return (nopen); +} + +static int +usalo_close(SCSI *usalp) +{ + register int f; + register int b; + register int t; + register int l; + + if (usalp->local == NULL) + return (-1); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + f = usallocal(usalp)->usalfiles[b][t][l]; + if (f >= 0) + close(f); + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + return (MAX_DMA_HP); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = valloc((size_t)(amt)); + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + 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); + + if (usalp->local == NULL) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if (usallocal(usalp)->usalfiles[busno][t][l] >= 0) + return (TRUE); + } + return (FALSE); +} + +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); + + if (usalp->local == NULL) + return (-1); + + return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]); +} + +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) +{ + if (what == SCG_RESET_NOP) + return (0); + if (what != SCG_RESET_BUS) { + errno = EINVAL; + return (-1); + } + return (ioctl(usalp->fd, SIOC_RESET_BUS, 0)); +} + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + int ret; + int flags; + struct sctl_io sctl_io; + + if ((usalp->fd < 0) || (sp->cdb_len > sizeof (sctl_io.cdb))) { + sp->error = SCG_FATAL; + return (0); + } + + fillbytes((caddr_t)&sctl_io, sizeof (sctl_io), '\0'); + + flags = 0; +/* flags = SCTL_INIT_WDTR|SCTL_INIT_SDTR;*/ + if (sp->flags & SCG_RECV_DATA) + flags |= SCTL_READ; + if ((sp->flags & SCG_DISRE_ENA) == 0) + flags |= SCTL_NO_ATN; + + sctl_io.flags = flags; + + movebytes(&sp->cdb, sctl_io.cdb, sp->cdb_len); + sctl_io.cdb_length = sp->cdb_len; + + sctl_io.data_length = sp->size; + sctl_io.data = sp->addr; + + if (sp->timeout == 0) + sctl_io.max_msecs = 0; + else + sctl_io.max_msecs = (sp->timeout * 1000) + 500; + + errno = 0; + sp->error = SCG_NO_ERROR; + sp->sense_count = 0; + sp->u_scb.cmd_scb[0] = 0; + sp->resid = 0; + + ret = ioctl(usalp->fd, SIOC_IO, &sctl_io); + if (ret < 0) { + sp->error = SCG_FATAL; + sp->ux_errno = errno; + return (ret); + } +if (usalp->debug > 0) +fprintf(stderr, "cdb_status: %X, size: %d xfer: %d\n", sctl_io.cdb_status, sctl_io.data_length, sctl_io.data_xfer); + + if (sctl_io.cdb_status == 0 || sctl_io.cdb_status == 0x02) + sp->resid = sp->size - sctl_io.data_xfer; + + if (sctl_io.cdb_status & SCTL_SELECT_TIMEOUT || + sctl_io.cdb_status & SCTL_INVALID_REQUEST) { + sp->error = SCG_FATAL; + } else if (sctl_io.cdb_status & SCTL_INCOMPLETE) { + sp->error = SCG_TIMEOUT; + } else if (sctl_io.cdb_status > 0xFF) { + errmsgno(EX_BAD, "SCSI problems: cdb_status: %X\n", sctl_io.cdb_status); + + } else if ((sctl_io.cdb_status & 0xFF) != 0) { + sp->error = SCG_RETRYABLE; + sp->ux_errno = EIO; + + sp->u_scb.cmd_scb[0] = sctl_io.cdb_status & 0xFF; + + sp->sense_count = sctl_io.sense_xfer; + if (sp->sense_count > SCG_MAX_SENSE) + sp->sense_count = SCG_MAX_SENSE; + + if (sctl_io.sense_status != S_GOOD) { + sp->sense_count = 0; + } else { + movebytes(sctl_io.sense, sp->u_sense.cmd_sense, sp->sense_count); + } + + } + return (ret); +} +#define sense u_sense.Sense diff --git a/libusal/scsi-linux-ata.c b/libusal/scsi-linux-ata.c new file mode 100644 index 0000000..3ec18b7 --- /dev/null +++ b/libusal/scsi-linux-ata.c @@ -0,0 +1,1188 @@ +/* + * 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-linux-ata.c 1.7 04/06/12 Copyright 2002 J. Schilling */ +/* + * Interface for Linux generic SCSI implementation (sg). + * + * This is the interface for the broken Linux SCSI generic driver. + * This is a hack, that tries to emulate the functionality + * of the usal driver. + * + * 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. + * + * Copyright (c) 2002 J. Schilling + * + * Thanks to Alexander Kern <alex.kern@gmx.de> for the idea and first + * code fragments for supporting the CDROM_SEND_PACKET ioctl() from + * the cdrom.c kernel driver. Please note that this interface in priciple + * is completely unneeded but the Linux kernel is just a cluster of + * code and does not support planned orthogonal interface systems. + * For this reason we need CDROM_SEND_PACKET in order to work around a + * bug in the linux kernel that prevents to use PCATA drives because + * the kernel panics if you try to put ide-scsi on top of the PCATA + * driver. + */ +/* + * 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. + */ + +#ifdef USE_OLD_ATAPI + +#define ata_sccsid "obsolete ATAPI driver in cdrkit" + +static char _usal_atrans_version[] = "scsi-linux-ata.c-1.7"; /* The version for ATAPI transport*/ + +static char *usalo_aversion(SCSI *usalp, int what); +static int usalo_ahelp(SCSI *usalp, FILE *f); +static int usalo_aopen(SCSI *usalp, char *device); +static int usalo_aclose(SCSI *usalp); +static long usalo_amaxdma(SCSI *usalp, long amt); +static BOOL usalo_ahavebus(SCSI *usalp, int); +static int usalo_afileno(SCSI *usalp, int, int, int); +static int usalo_ainitiator_id(SCSI *usalp); +static int usalo_aisatapi(SCSI *usalp); +static int usalo_areset(SCSI *usalp, int what); +static int usalo_asend(SCSI *usalp); + +static usal_ops_t ata_ops = { + usalo_asend, + usalo_aversion, + usalo_ahelp, + usalo_aopen, + usalo_aclose, + usalo_amaxdma, + usalo_getbuf, /* Shared with SG driver */ + usalo_freebuf, /* Shared with SG driver */ + usalo_ahavebus, + usalo_afileno, + usalo_ainitiator_id, + usalo_aisatapi, + usalo_areset, +}; + +#define HOST_EMPTY 0xF +#define HOST_SCSI 0x0 +#define HOST_IDE 0x1 +#define HOST_USB 0x2 +#define HOST_IEEE1389 0x3 +#define HOST_PARALLEL 0x4 +#define HOST_OTHER 0xE + + +#define typlocal(p, schillybus) usallocal(p)->bc[schillybus].typ +#define buslocal(p, schillybus) usallocal(p)->bc[schillybus].bus +#define hostlocal(p, schillybus) usallocal(p)->bc[schillybus].host + +#define MAX_DMA_ATA (131072-1) /* EINVAL (hart) ENOMEM (weich) bei mehr ... */ + /* Bei fehlerhaftem Sense Pointer kommt EFAULT */ + +static int usalo_send(SCSI * usalp); +static BOOL sg_amapdev(SCSI * usalp, int f, char *device, int *bus, + int *target, int *lun); +static BOOL sg_amapdev_scsi(SCSI * usalp, int f, int *busp, int *tgtp, + int *lunp, int *chanp, int *inop); +static int usalo_aget_first_free_shillybus(SCSI * usalp, int subsystem, + int host, int bus); +static int usalo_amerge(char *path, char *readedlink, char *buffer, int buflen); + +/* + * uncomment this when you will get a debug file #define DEBUG + */ +#ifdef DEBUG +#define LOGFILE "scsi-linux-ata.log" +#define log(a) sglog a + +static void sglog(const char *fmt, ...); + +#include <vadefs.h> + +/* VARARGS1 */ +static void +sglog(const char *fmt, ...) +{ + va_list args; + FILE *f = fopen(LOGFILE, "a"); + + if (f == NULL) + return; + + va_start(args, fmt); + vfprintf(f, fmt, args); + va_end(args); + fclose(f); +} +#else +#define log(a) +#endif /* DEBUG */ + +static int scan_internal(SCSI * usalp, int *fatal); + +/* + * 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_aversion(SCSI *usalp, int what) +{ + if (usalp != (SCSI *)0) { + switch (what) { + + case SCG_VERSION: + return (_usal_atrans_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 (ata_sccsid); + } + } + return ((char *)0); +} + +static int +usalo_ahelp(SCSI *usalp, FILE *f) +{ + __usal_help(f, "ATA", "ATA Packet specific SCSI transport", + "ATAPI:", "bus,target,lun", "ATAPI:1,2,0", TRUE, FALSE); + return (0); +} + +static int +usalo_aopen(SCSI *usalp, char *device) +{ + int bus = usal_scsibus(usalp); + int target = usal_target(usalp); + int lun = usal_lun(usalp); + + register int f; + register int b; + register int t; + register int l; + int nopen = 0; + + if (usalp->overbose) + fprintf(stderr, "Warning: Using ATA Packet interface.\n"); + if (usalp->overbose) { + fprintf(stderr, "Warning: The related Linux kernel interface code seems to be unmaintained.\n"); + fprintf(stderr, "Warning: There is absolutely NO DMA, operations thus are slow.\n"); + } + + log(("\n<<<<<<<<<<<<<<<< LOGGING ON >>>>>>>>>>>>>>>>>\n")); + if (bus >= MAX_SCHILLY_HOSTS || target >= MAX_TGT || lun >= MAX_LUN) { + errno = EINVAL; + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Illegal value for bus, target or lun '%d,%d,%d'", + bus, target, lun); + + return (-1); + } + + if (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) { + return (0); + } + + usallocal(usalp)->usalfile = -1; + usallocal(usalp)->pgbus = -2; + usallocal(usalp)->SCSIbuf = (char *)-1; + usallocal(usalp)->pack_id = 5; + usallocal(usalp)->drvers = -1; + usallocal(usalp)->isold = -1; + usallocal(usalp)->xbufsize = 0L; + usallocal(usalp)->xbuf = NULL; + + + for (b = 0; b < MAX_SCHILLY_HOSTS; b++) { + typlocal(usalp, b) = HOST_EMPTY; + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + usallocal(usalp)->usalfiles[b][t][l] = (short) -1; + } + } + } + + if (device != NULL && strcmp(device, "ATAPI") == 0) + goto atascan; + + /* if not scanning */ + if ((device != NULL && *device != '\0') || (bus == -2 && target == -2)) + goto openbydev; + +atascan: + if (scan_internal(usalp, &nopen)) { + if (usalp->errstr) + printf(usalp->errstr, "INFO: scan_internal(...) failed"); + return (-1); + } + return (nopen); + +openbydev: + if (device != NULL && strncmp(device, "ATAPI:", 6) == 0) + device += 6; + if (usalp->debug > 3) { + fprintf((FILE *) usalp->errfile, "INFO: do usalo_open openbydev"); + } + if (device != NULL && *device != '\0') { + int schilly_bus, + starget, + slun; + + f = sg_open_excl(device, O_RDONLY | O_NONBLOCK, FALSE); + + if (f < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", device); + return (0); + } + if (sg_amapdev(usalp, f, device, &schilly_bus, &starget, &slun)) { + usal_settarget(usalp, schilly_bus, starget, slun); + return (++nopen); + } + } + return (nopen); +} + +static int +scan_internal(SCSI *usalp, int *nopen) +{ + int i, + f; + int schilly_bus, + target, + lun; + char device[128]; + /* + * try always with devfs + * unfortunatelly the solution with test of existing + * of '/dev/.devfsd' don't work, because it root.root 700 + * and i don't like run suid root + */ + BOOL DEVFS = TRUE; + + if (DEVFS) { + for (i = 0; ; i++) { + sprintf(device, "/dev/cdroms/cdrom%i", i); + if ((f = open(device, O_RDONLY | O_NONBLOCK)) < 0) { + if (errno != ENOENT && errno != ENXIO && errno != ENODEV && errno != EACCES) { + if (usalp->debug > 4) { + fprintf((FILE *) usalp->errfile, + "try open(%s) return %i, errno %i, cancel\n", device, f, errno); + } + return (-2); + } else if (errno == ENOENT || errno == ENODEV) { + if (usalp->debug > 4) { + fprintf((FILE *) usalp->errfile, + "try open(%s) return %i, errno %i\n", device, f, errno); + } + if (0 == i) { + DEVFS = FALSE; + if (usalp->debug > 4) { + fprintf((FILE *) usalp->errfile, + "DEVFS not detected, continuing with old dev\n"); + } + } + break; + } + if (usalp->debug > 4) { + if (errno == EACCES) { + fprintf((FILE *) usalp->errfile, + "errno (EACCESS), you don't have the needed rights for %s\n", + device); + } + fprintf((FILE *) usalp->errfile, + "try open(%s) return %i, errno %i, trying next cdrom\n", + device, f, errno); + } + } else { + if (usalp->debug > 4) { + fprintf((FILE *) usalp->errfile, + "try open(%s) return %i errno %i calling sg_mapdev(...)\n", + device, f, errno); + } + if (sg_amapdev(usalp, f, device, &schilly_bus, &target, &lun)) { + (++(*nopen)); + } else { + close(f); + } + } + } + } + if (!DEVFS) { + /* for /dev/sr0 - /dev/sr? */ + for (i = 0; i<16 ; i++) { + sprintf(device, "/dev/sr%i", i); + if ((f = open(device, O_RDONLY | O_NONBLOCK)) < 0) { + if (errno != ENOENT && errno != ENXIO && errno != ENODEV && errno != EACCES) { + if (usalp->debug > 4) { + fprintf((FILE *) usalp->errfile, + "try open(%s) return %i, errno %i, cancel\n", + device, f, errno); + } + return (-2); + } + } else { + if (sg_amapdev(usalp, f, device, &schilly_bus, &target, &lun)) { + (++(*nopen)); + } else { + close(f); + } + } + } + + /* for /dev/hda - /dev/hdz */ + for (i = 'a'; i <= 'z'; i++) { + sprintf(device, "/dev/hd%c", i); + if ((f = open(device, O_RDONLY | O_NONBLOCK)) < 0) { + if (errno != ENOENT && errno != ENXIO && errno != EACCES) { + if (usalp->debug > 4) { + fprintf((FILE *) usalp->errfile, + "try open(%s) return %i, errno %i, cancel\n", + device, f, errno); + } + return (-2); + } + } else { + /* ugly hack, make better, when you can. Alex */ + if (0 > ioctl(f, CDROM_DRIVE_STATUS, CDSL_CURRENT)) { + if (usalp->debug > 4) { + fprintf((FILE *) usalp->errfile, + "%s is not a cdrom, skipping\n", + device); + } + close(f); + } else if (sg_amapdev(usalp, f, device, &schilly_bus, &target, &lun)) { + (++(*nopen)); + } else { + close(f); + } + } + } + } + return (0); +} + +static int +usalo_aclose(SCSI *usalp) +{ + register int f; + register int h; + register int t; + register int l; + + if (usalp->local == NULL) + return (-1); + + for (h = 0; h < MAX_SCHILLY_HOSTS; h++) { + typlocal(usalp, h) = (HOST_EMPTY); + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + f = usallocal(usalp)->usalfiles[h][t][l]; + if (f >= 0) + close(f); + usallocal(usalp)->usalfiles[h][t][l] = (short) -1; + } + } + } + + if (usallocal(usalp)->xbuf != NULL) { + free(usallocal(usalp)->xbuf); + usallocal(usalp)->xbufsize = 0L; + usallocal(usalp)->xbuf = NULL; + } + log(("<<<<<<<<<<<<<<<< LOGGING OFF >>>>>>>>>>>>>>>>>\n\n")); + return (0); +} + +static int +usalo_aget_first_free_shillybus(SCSI *usalp, int subsystem, int host, int bus) +{ + int first_free_schilly_bus; + + for (first_free_schilly_bus = 0; + first_free_schilly_bus < MAX_SCHILLY_HOSTS; + first_free_schilly_bus++) { + + if (typlocal(usalp, first_free_schilly_bus) == HOST_EMPTY || + (typlocal(usalp, first_free_schilly_bus) == subsystem && + hostlocal(usalp, first_free_schilly_bus) == host && + buslocal(usalp, first_free_schilly_bus) == bus)) + break; + } + + if (first_free_schilly_bus >= MAX_SCHILLY_HOSTS) { + errmsgno(EX_BAD, "ERROR: in usalo_get_first_free_shillybus(...). Too many CDROMs, more than %i", + MAX_SCHILLY_HOSTS); + errmsgno(EX_BAD, "Increase MAX_SCHILLY_HOSTS in scsi-linux-ata.c and recompile!"); + return (-1); + } + return (first_free_schilly_bus); +} + +static int +usalo_amerge(char *path, char *readedlink, char *buffer, int buflen) +{ + char *aa; + +#define TOKEN_ARRAY 20 +#define LAST_CHAR(x) (x)[strlen((x))-1] +#define ONE_CHAR_BACK(x) (x)[strlen((x))-1] = '\0' + char *ppa[TOKEN_ARRAY]; + char *pa; + + int i; + int len; + char seps[] = "/"; + char *last_slash; + + if (!path || !readedlink || !buffer) + return (-EINVAL); + + if ('/' == readedlink[0]) { + aa = (char *) malloc(strlen(readedlink) + 1); + if (!aa) + return (-ENOMEM); + + strcpy(aa, readedlink); + } else { + aa = (char *) malloc(strlen(path) + strlen(readedlink) + 1); + if (!aa) + return (-ENOMEM); + + strcpy(aa, path); + if (LAST_CHAR(aa) == '/') { + ONE_CHAR_BACK(aa); + } + last_slash = strrchr(aa, '/'); + if (last_slash == NULL) + strcpy(aa, "/"); + else + *(++last_slash) = '\0'; + strcat(aa, readedlink); + } + memset(ppa, 0x00, sizeof (ppa)); + + for (i = 0, pa = strtok(aa, seps); + i < TOKEN_ARRAY && pa != NULL; + ++i, pa = strtok(NULL, seps)) { + ppa[i] = pa; + } + + if (i == TOKEN_ARRAY) { + free(aa); + return (-ENOMEM); + } + for (i = 0; i < TOKEN_ARRAY && ppa[i]; i++) { + if (strcmp(ppa[i], "..") == 0) { + ppa[i] = NULL; + if (i > 1) + ppa[i - 1] = NULL; + } + } + + /* dry run */ + len = 0; + for (i = 0; i < TOKEN_ARRAY; i++) { + if (ppa[i]) { + len += 1; + len += strlen(ppa[i]); + } + } + if (0 == len) + len = 1; + + if (len + 1 <= buflen) { + strcpy(buffer, ""); + for (i = 0; i < TOKEN_ARRAY; i++) { + if (ppa[i]) { + strcat(buffer, "/"); + strcat(buffer, ppa[i]); + } + } + + if (strlen(buffer) == 0) + strcpy(buffer, "/"); + } + free(aa); + + return (len + 1); +} + +/* + * /dev/cdroms/cdrom0 first CD-ROM + * /dev/cdroms/cdrom1 second CD-ROM + * + * + * SCSI Devices + * + * To uniquely identify any SCSI device requires the following information: + * + * controller (host adapter) + * bus (SCSI channel) + * target (SCSI ID) + * unit (Logical Unit Number) + * + * All SCSI devices are placed under /dev/scsi (assuming devfs is mounted on /dev). + * Hence, a SCSI device with the following parameters: + * c=1,b=2,t=3,u=4 would appear as: + * + * /dev/scsi/host1/bus2/target3/lun4 device directory + * + * Inside this directory, a number of device entries may be created, + * depending on which SCSI device-type drivers were installed. + * + * See the section on the disc naming scheme to see what entries + * the SCSI disc driver creates. + * + * See the section on the tape naming scheme to see what entries + * the SCSI tape driver creates. + * + * The SCSI CD-ROM driver creates: cd + * The SCSI generic driver creates: generic + * + * IDE Devices + * + * To uniquely identify any IDE device requires the following information: + * + * controller + * bus (0/1 aka. primary/secondary) + * target (0/1 aka. master/slave) + * unit + * + * All IDE devices are placed under /dev/ide, and uses a similar + * naming scheme to the SCSI subsystem. + * + * + * Example /dev/cdroms/cdrom0 -> /dev/scsi/host1/bus2/target3/lun4/cd + * Example /dev/cdroms/cdrom1 -> /dev/ide/host1/bus0/target1/lun4/cd + * + */ +static BOOL +sg_amapdev(SCSI *usalp, int f, char *device, int *schillybus, int *target, + int *lun) +{ + struct host { + char host[4]; + char host_no; + }; + struct bus { + char bus[3]; + char bus_no; + }; + struct target { + char target[6]; + char target_no; + }; + struct lun { + char lun[3]; + char lun_no; + }; + + int h, + b, + t, + l; + +#define TOKEN_DEV "dev" +#define TOKEN_SUBSYSTEM_SCSI "scsi" +#define TOKEN_SUBSYSTEM_IDE "ide" +#define TOKEN_HOST "host" +#define TOKEN_BUS "bus" +#define TOKEN_TARGET "target" +#define TOKEN_LUN "lun" +#define TOKEN_CD "cd" + +#define ID_TOKEN_DEV 0 +#define ID_TOKEN_SUBSYSTEM 1 +#define ID_TOKEN_HOST 2 +#define ID_TOKEN_BUS 3 +#define ID_TOKEN_TARGET 4 +#define ID_TOKEN_LUN 5 +#define ID_TOKEN_CD 6 +#define ID_TOKEN_LAST ID_TOKEN_CD +#define ID_TOKEN_MAX ID_TOKEN_LAST + 2 +#define CHARTOINT(x) (abs(atoi(&x))) + + char *token[ID_TOKEN_MAX], + *seps = "/"; + int i, + result; + struct stat buf; + +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif +#define LOCAL_MAX_PATH MAX_PATH + char tmp[LOCAL_MAX_PATH], + tmp1[LOCAL_MAX_PATH]; + int first_free_schilly_bus; + int subsystem = HOST_EMPTY; + + /* old DEV */ + typedef struct { + char prefix[2]; + char device; + } old_dev; + /* strtok need char* instead of const char* */ + result = stat(device, &buf); + if (result || !S_ISBLK(buf.st_mode)) + return (FALSE); + + result = lstat(device, &buf); + if (!result && S_ISLNK(buf.st_mode)) { + result = readlink(device, tmp, LOCAL_MAX_PATH); + if (result > 0 && result < LOCAL_MAX_PATH) { + tmp[result] = '\0'; + + result = usalo_amerge(device, tmp, tmp1, LOCAL_MAX_PATH); + if (result > 0 && result < LOCAL_MAX_PATH) { + tmp1[result] = '\0'; + strcpy(tmp, tmp1); + } else { + errmsgno(EX_BAD, + "ERROR: with link merging! base %s link %s, result of merging %i\n", + device, tmp, result); + return (FALSE); + } + } else { + errmsgno(EX_BAD, + "ERROR: with link reading! link %s, result of readlink %i\n", + device, result); + return (FALSE); + } + } else { + strncpy(tmp, device, sizeof (tmp)); + } + if (usalp->debug > 3) { + fprintf((FILE *) usalp->errfile, "INFO: %s -> %s\n", device, tmp); + } + memset(token, 0x00, sizeof (token)); + i = 0; + token[i] = strtok(tmp, seps); + while (token[i] != NULL && (++i) && i < ID_TOKEN_MAX) { + token[i] = strtok(NULL, seps); + } + + if (i == ID_TOKEN_MAX || + !(token[ID_TOKEN_DEV]) || + strcmp(token[ID_TOKEN_DEV], TOKEN_DEV)) { + + errmsgno(EX_BAD, "ERROR: unknown format\n"); + errmsgno(EX_BAD, "EXAMPLE: /dev/scsi/host1/bus2/target3/lun4/cd\n"); + errmsgno(EX_BAD, "EXAMPLE: /dev/ide/host0/bus0/target1/lun0/cd\n"); + errmsgno(EX_BAD, "EXAMPLE: /dev/hda or /dev/sr0\n"); + return (FALSE); + } + if (!(strcmp(token[ID_TOKEN_SUBSYSTEM], TOKEN_SUBSYSTEM_SCSI)) || + !(strcmp(token[ID_TOKEN_SUBSYSTEM], TOKEN_SUBSYSTEM_IDE))) { + h = CHARTOINT(((struct host *) token[ID_TOKEN_HOST])->host_no); + b = CHARTOINT(((struct bus *) token[ID_TOKEN_BUS])->bus_no); + t = CHARTOINT(((struct target *) token[ID_TOKEN_TARGET])->target_no); + l = CHARTOINT(((struct lun *) token[ID_TOKEN_LUN])->lun_no); +#ifdef PARANOID + if (strncmp(token[ID_TOKEN_HOST], TOKEN_HOST, strlen(TOKEN_HOST))) { + log(("ERROR: invalid host specified\n")); + return (FALSE); + } + if (strncmp(token[ID_TOKEN_BUS], TOKEN_BUS, strlen(TOKEN_BUS))) { + log(("ERROR: invalid bus specified\n")); + return (FALSE); + } + if (strncmp(token[ID_TOKEN_TARGET], TOKEN_TARGET, strlen(TOKEN_TARGET))) { + log(("ERROR: invalid target specified\n")); + return (FALSE); + } + if (strncmp(token[ID_TOKEN_LUN], TOKEN_LUN, strlen(TOKEN_LUN))) { + log(("ERROR: invalid lun specified\n")); + return (FALSE); + } + if (!(strcmp(token[ID_TOKEN_SUBSYSTEM], TOKEN_SUBSYSTEM_IDE))) { + if (b > 1 || t > 1) { + log(("ERROR: invalid bus or target for IDE specified\n")); + return (FALSE); + } + } +#endif /* PARANOID */ + + if (!(strcmp(token[ID_TOKEN_SUBSYSTEM], TOKEN_SUBSYSTEM_IDE))) { + subsystem = HOST_IDE; + } else if (!(strcmp(token[ID_TOKEN_SUBSYSTEM], TOKEN_SUBSYSTEM_SCSI))) { + subsystem = HOST_SCSI; + } else { + subsystem = HOST_OTHER; + } + } else if (!token[ID_TOKEN_HOST] && + strlen(token[ID_TOKEN_SUBSYSTEM]) == sizeof (old_dev)) { + char j; + + old_dev *pDev = (old_dev *) token[ID_TOKEN_SUBSYSTEM]; + + if (strncmp(pDev->prefix, "hd", 2) == 0) { + j = pDev->device - ('a'); + + subsystem = HOST_IDE; + h = j / 4; + b = (j % 4) / 2; + t = (j % 4) % 2; + l = 0; + } else if (strncmp(pDev->prefix, "sr", 2) == 0) { +#ifdef nonono + if (pDev->device >= '0' && pDev->device <= '9') + j = pDev->device - ('0'); + else + j = pDev->device - ('a'); + + + h = j / 4; + b = (j % 4) / 2; + t = (j % 4) % 2; + l = 0; +#endif /* nonono */ + /* other solution, with ioctl */ + int Chan = 0, + Ino = 0, + Bus = 0, + Target = 0, + Lun = 0; + + subsystem = HOST_SCSI; + sg_amapdev_scsi(usalp, f, &Bus, &Target, &Lun, &Chan, &Ino); + + /* For old kernels try to make the best guess. */ +#ifdef nonono + int n; + Ino |= Chan << 8; + n = sg_mapbus(usalp, Bus, Ino); + if (Bus == -1) { + Bus = n; + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "SCSI Bus: %d (mapped from %d)\n", + Bus, Ino); + } + } +/* It is me too high ;-()*/ +#endif /* nonono */ + h = Ino; + b = Chan; + t = Target; + l = Lun; + } else { + errmsgno(EX_BAD, "ERROR: unknow subsystem (%s) in (%s)\n", + token[ID_TOKEN_SUBSYSTEM], device); + return (FALSE); + } + } else { + errmsgno(EX_BAD, "ERROR: unknow subsystem (%s) in (%s)\n", + token[ID_TOKEN_SUBSYSTEM], device); + return (FALSE); + } + + if (usalp->verbose) + printf(usalp->errstr, "INFO: subsystem %s: h %i, b %i, t %i, l %i", + token[ID_TOKEN_SUBSYSTEM], h, b, t, l); + + first_free_schilly_bus = usalo_aget_first_free_shillybus(usalp, subsystem, h, b); + if (-1 == first_free_schilly_bus) { + return (FALSE); + } + if (usallocal(usalp)->usalfiles[first_free_schilly_bus][t][l] != (-1)) { + errmsgno(EX_BAD, "ERROR: this cdrom is already mapped %s(%d,%d,%d)\n", + device, first_free_schilly_bus, t, l); + return (FALSE); + } else { + usallocal(usalp)->usalfiles[first_free_schilly_bus][t][l] = f; + typlocal(usalp, first_free_schilly_bus) = subsystem; + hostlocal(usalp, first_free_schilly_bus) = h; + buslocal(usalp, first_free_schilly_bus) = b; + *schillybus = first_free_schilly_bus; + *target = t; + *lun = l; + + if (usalp->debug > 1) { + fprintf((FILE *) usalp->errfile, + "INFO: /dev/%s, (host%d/bus%d/target%d/lun%d) will be mapped on the schilly bus No %d (%d,%d,%d)\n", + token[ID_TOKEN_SUBSYSTEM], h, b, t, l, + first_free_schilly_bus, first_free_schilly_bus, t, l); + } + } + return (TRUE); +} + +static BOOL +sg_amapdev_scsi(SCSI *usalp, int f, int *busp, int *tgtp, int *lunp, + int *chanp, int *inop) +{ + struct sg_id { + long l1; /* target | lun << 8 | channel << 16 | low_ino << 24 */ + long l2; /* Unique id */ + } sg_id; + int Chan; + int Ino; + int Bus; + int Target; + int Lun; + + if (ioctl(f, SCSI_IOCTL_GET_IDLUN, &sg_id)) + return (FALSE); + + if (usalp->debug > 0) { + fprintf((FILE *) usalp->errfile, + "INFO: l1: 0x%lX l2: 0x%lX\n", sg_id.l1, sg_id.l2); + } + if (ioctl(f, SCSI_IOCTL_GET_BUS_NUMBER, &Bus) < 0) { + Bus = -1; + } + Target = sg_id.l1 & 0xFF; + Lun = (sg_id.l1 >> 8) & 0xFF; + Chan = (sg_id.l1 >> 16) & 0xFF; + Ino = (sg_id.l1 >> 24) & 0xFF; + if (usalp->debug > 0) { + fprintf((FILE *) usalp->errfile, + "INFO: Bus: %d Target: %d Lun: %d Chan: %d Ino: %d\n", + Bus, Target, Lun, Chan, Ino); + } + *busp = Bus; + *tgtp = Target; + *lunp = Lun; + if (chanp) + *chanp = Chan; + if (inop) + *inop = Ino; + return (TRUE); +} + +static long +usalo_amaxdma(SCSI *usalp, long amt) +{ + /* + * EINVAL (hart) ENOMEM (weich) bei mehr ... + * Bei fehlerhaftem Sense Pointer kommt EFAULT + */ + return (MAX_DMA_ATA); +} + +static BOOL +usalo_ahavebus(SCSI *usalp, int busno) +{ + register int t; + register int l; + + if (busno < 0 || busno >= MAX_SCHILLY_HOSTS) + return (FALSE); + + if (usalp->local == NULL) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if (usallocal(usalp)->usalfiles[busno][t][l] >= 0) + return (TRUE); + } + return (FALSE); +} + +static int +usalo_afileno(SCSI *usalp, int busno, int tgt, int tlun) +{ + if (busno < 0 || busno >= MAX_SCHILLY_HOSTS || + tgt < 0 || tgt >= MAX_TGT || + tlun < 0 || tlun >= MAX_LUN) + return (-1); + + if (usalp->local == NULL) + return (-1); + + return ((int) usallocal(usalp)->usalfiles[busno][tgt][tlun]); +} + +static int +usalo_ainitiator_id(SCSI *usalp) +{ + printf(usalp->errstr, "NOT IMPELEMENTED: usalo_initiator_id"); + return (-1); +} + +static int +usalo_aisatapi(SCSI *usalp) +{ + int schillybus = usalp->addr.scsibus; + int typ = typlocal(usalp, schillybus); + if (typ == HOST_EMPTY) + return (-1); + if (typ != HOST_SCSI) + return (1); + else + return (0); +} + +static int +usalo_areset(SCSI *usalp, int what) +{ + if (what == SCG_RESET_NOP) + return (0); + + if (what == SCG_RESET_TGT || what == SCG_RESET_BUS) + return (ioctl(what, CDROMRESET)); + + return (-1); +} + +static int +usalo_asend(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + int ret, + i; + struct cdrom_generic_command sg_cgc; + struct request_sense sense_cgc; + +#ifdef DEBUG + char tmp_send[340], + tmp_read[340], + tmp_sense[340], + tmp1[30]; + int j; + char *p; +#endif + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + sp->ux_errno = EIO; + return (0); + } + if (sp->cdb_len > CDROM_PACKET_SIZE) { + sp->error = SCG_FATAL; + sp->ux_errno = EIO; + return (0); + } + /* initialize */ + fillbytes((caddr_t) & sg_cgc, sizeof (sg_cgc), '\0'); + fillbytes((caddr_t) & sense_cgc, sizeof (sense_cgc), '\0'); + + if (sp->flags & SCG_RECV_DATA) { + sg_cgc.data_direction = CGC_DATA_READ; + } else if (sp->size > 0) { + sg_cgc.data_direction = CGC_DATA_WRITE; + } else { + sg_cgc.data_direction = CGC_DATA_NONE; + } +#if LINUX_VERSION_CODE >= 0x020403 + if (sp->flags & SCG_SILENT) { + sg_cgc.quiet = 1; + } +#endif + for (i = 0; i < sp->cdb_len; i++) { + sg_cgc.cmd[i] = sp->cdb.cmd_cdb[i]; + } + + sg_cgc.buflen = sp->size; + sg_cgc.buffer = (unsigned char *)sp->addr; + + if (sp->sense_len > sizeof (sense_cgc)) + sense_cgc.add_sense_len = sizeof (sense_cgc) - 8; + else + sense_cgc.add_sense_len = sp->sense_len - 8; + + sg_cgc.sense = &sense_cgc; +#if LINUX_VERSION_CODE >= 0x020403 + sg_cgc.timeout = sp->timeout * 1000; +#endif +#ifdef DEBUG + strcpy(tmp_send, "send cmd:\n"); + for (j = 0; j < sp->cdb_len; j++) { + sprintf(tmp1, " %02X", sp->cdb.cmd_cdb[j]); + strcat(tmp_send, tmp1); + } + strcat(tmp_send, "\n"); + + if (sg_cgc.data_direction == CGC_DATA_WRITE) { + int z; + + sprintf(tmp1, "data_write: %i bytes\n", sp->size); + strcat(tmp_send, tmp1); + for (j = 0, z = 1; j < 80 && j < sp->size; j++, z++) { + if (z > 16) { + z = 1; + strcat(tmp_send, "\n"); + } + sprintf(tmp1, " %02X", (unsigned char) (sp->addr[j])); + strcat(tmp_send, tmp1); + } + strcat(tmp_send, "\n"); + + if (sp->size > 80) { + strcat(tmp_send, "...\n"); + } + } +#endif /* DEBUG */ + if ((ret = ioctl(usalp->fd, CDROM_SEND_PACKET, &sg_cgc)) < 0) + sp->ux_errno = geterrno(); + + if (ret < 0 && usalp->debug > 4) { + fprintf((FILE *) usalp->errfile, + "ioctl(CDROM_SEND_PACKET) ret: %d\n", ret); + } + /* + * copy scsi data back + */ + if (sp->flags & SCG_RECV_DATA && ((void *) sp->addr != (void *) sg_cgc.buffer)) { + memcpy(sp->addr, sg_cgc.buffer, (sp->size < sg_cgc.buflen) ? sp->size : sg_cgc.buflen); + if (sg_cgc.buflen > sp->size) + sp->resid = sg_cgc.buflen - sp->size; + } + sp->error = SCG_NO_ERROR; +#ifdef DEBUG + if (ret < 0) { + switch (sp->ux_errno) { + case ENOTTY: + p = "ENOTTY"; + break; + case EINVAL: + p = "EINVAL"; + break; + case ENXIO: + p = "ENXIO"; + break; + case EACCES: + p = "EACCES"; + break; + case EIO: + p = "EIO"; + break; + case ENOMEDIUM: + p = "ENOMEDIUM"; + break; + case EDRIVE_CANT_DO_THIS: + p = "EDRIVE_CANT_DO_THIS"; + break; + default: + p = "UNKNOW"; + }; + log(("%s", tmp_send)); + log(("ERROR: returns %i errno %i(%s)\n", ret, sp->ux_errno, p)); + } +#endif /* DEBUG */ + if (ret < 0) { + /* + * Check if SCSI command cound not be send at all. + * Linux usually returns EINVAL for an unknoen ioctl. + * In case somebody from the Linux kernel team learns that the + * corect errno would be ENOTTY, we check for this errno too. + */ + if (sp->ux_errno == EINVAL) { + /* + * Try to work around broken Linux kernel design... + * If SCSI Sense Key is 0x05 (Illegal request), Linux + * returns a useless EINVAL making it close to + * impossible distinct from "Illegal ioctl()" or + * "Invalid parameter". + */ + if ((((Uchar *)sg_cgc.sense)[0] != 0) || + (((Uchar *)sg_cgc.sense)[2] != 0)) + sp->ux_errno = EIO; + + } else if ((sp->ux_errno == ENOTTY || sp->ux_errno == EINVAL)) { + /* + * May be "Illegal ioctl()". + */ + return (-1); + } + if (sp->ux_errno == ENXIO || sp->ux_errno == EACCES) { + return (-1); + } + } else if (ret == 0) { +#ifdef DEBUG + if (sg_cgc.data_direction == CGC_DATA_READ) { + int z; + + sprintf(tmp_read, "data_read: %i bytes\n", sp->size); + for (j = 0, z = 1; j < 80 && j < sp->size; j++, z++) { + if (z > 16) { + z = 1; + strcat(tmp_read, "\n"); + } + sprintf(tmp1, " %02X", (unsigned char) (sp->addr[j])); + strcat(tmp_read, tmp1); + } + strcat(tmp_read, "\n"); + if (sp->size > 80) { + strcat(tmp_read, "...\n"); + } + } +#endif /* DEBUG */ + } + /* + * copy sense back + */ + if (ret < 0 && sg_cgc.sense->error_code) { + sp->sense_count = sense_cgc.add_sense_len + 8; +#ifdef DEBUG + sprintf(tmp_sense, "sense_data: length %i\n", sp->sense_count); + for (j = 0; j < sp->sense_count; j++) { + sprintf(tmp1, " %02X", (((unsigned char *) (&sense_cgc))[j])); + strcat(tmp_sense, tmp1); + } + log(("%s\n", tmp_sense)); + + sprintf(tmp_sense, "sense_data: error code 0x%02X, sense key 0x%02X," + " additional length %i, ASC 0x%02X, ASCQ 0x%02X\n", + sg_cgc.sense->error_code, sg_cgc.sense->sense_key, + sg_cgc.sense->add_sense_len, sg_cgc.sense->asc, + sg_cgc.sense->ascq); + + log(("%s\n", tmp_sense)); +#endif /* DEBUG */ + memcpy(sp->u_sense.cmd_sense, /* (caddr_t) */ &sense_cgc, SCG_MAX_SENSE); + sp->u_scb.cmd_scb[0] = ST_CHK_COND; + + switch (sg_cgc.sense->sense_key) { + case SC_UNIT_ATTENTION: + case SC_NOT_READY: + sp->error = SCG_RETRYABLE; /* may be BUS_BUSY */ + sp->u_scb.cmd_scb[0] |= ST_BUSY; + break; + case SC_ILLEGAL_REQUEST: + break; + default: + break; + } + } else { + sp->u_scb.cmd_scb[0] = 0x00; + } + + sp->resid = 0; + return (0); +} +#endif /* USE_OLD_ATAPI */ diff --git a/libusal/scsi-linux-pg.c b/libusal/scsi-linux-pg.c new file mode 100644 index 0000000..00edf5d --- /dev/null +++ b/libusal/scsi-linux-pg.c @@ -0,0 +1,587 @@ +/* + * 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-linux-pg.c 1.43 04/01/15 Copyright 1997 J. Schilling */ +/* + * Interface for the Linux PARIDE implementation. + * + * We emulate the functionality of the usal driver, via the pg driver. + * + * 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. + * + * Copyright (c) 1997 J. Schilling + * Copyright (c) 1998 Grant R. Guenther <grant@torque.net> + * Under the terms of the GNU public license. + */ +/* + * 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. + */ + +#include <string.h> +#ifdef HAVE_LINUX_PG_H +#include <linux/pg.h> +#else +#include "pg.h" /* Use local version as Linux sometimes doesn't have */ +#endif /* installed. Now libusal always supports PP SCSI */ + +/* + * 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_pg[] = "scsi-linux-pg.c-1.43"; /* The version for this transport*/ + +#ifdef USE_PG_ONLY + +#define MAX_SCG 1 /* Max # of SCSI controllers */ +#define MAX_TGT 8 +#define MAX_LUN 8 + +struct usal_local { + short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN]; + short buscookies[MAX_SCG]; + int pgbus; + char *SCSIbuf; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +#else + +#define usalo_version pg_version +#define usalo_help pg_help +#define usalo_open pg_open +#define usalo_close pg_close +#define usalo_send pg_send +#define usalo_maxdma pg_maxdma +#define usalo_initiator_id pg_initiator_id +#define usalo_isatapi pg_isatapi +#define usalo_reset pg_reset + +static char *pg_version(SCSI *usalp, int what); +static int pg_help(SCSI *usalp, FILE *f); +static int pg_open(SCSI *usalp, char *device); +static int pg_close(SCSI *usalp); +static long pg_maxdma(SCSI *usalp, long amt); +static int pg_initiator_id(SCSI *usalp); +static int pg_isatapi(SCSI *usalp); +static int pg_reset(SCSI *usalp, int what); +static int pg_send(SCSI *usalp); + +#endif + +static int do_usal_cmd(SCSI *usalp, struct usal_cmd *sp); +static int do_usal_sense(SCSI *usalp, struct usal_cmd *sp); + + +/* + * 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_pg); + /* + * 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, "pg", "SCSI transport for ATAPI over Parallel Port", + "", "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); + register int f; + register int b; +#ifdef USE_PG_ONLY + register int t; + register int l; +#endif + register int nopen = 0; + char devname[32]; + + 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); + } + +#ifndef USE_PG_ONLY + /* + * We need to find a fake bus number for the parallel port interface. + * Unfortunatly, the buscookie array may contain holes if + * SCSI_IOCTL_GET_BUS_NUMBER works, so we are searching backwards + * for some place for us. + * XXX Should add extra space in buscookies for a "PP bus". + */ + + if (usallocal(usalp)->buscookies[MAX_SCG-1] != (short)-1) + return (0); /* No space for pgbus */ + + for (b = MAX_SCG-1; b >= 0; b--) { + if (usallocal(usalp)->buscookies[b] != (short)-1) { + usallocal(usalp)->pgbus = ++b; + break; + } + } + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "PP Bus: %d\n", usallocal(usalp)->pgbus); + } +#else + if (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + + usallocal(usalp)->pgbus = -2; + usallocal(usalp)->SCSIbuf = (char *)-1; + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } +#endif + if (usallocal(usalp)->pgbus < 0) + usallocal(usalp)->pgbus = 0; + + if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) + goto openbydev; + + if (busno >= 0 && tgt >= 0 && tlun >= 0) { +#ifndef USE_PG_ONLY + if (usallocal(usalp)->pgbus != busno) + return (0); +#endif + snprintf(devname, sizeof (devname), "/dev/pg%d", tgt); + f = sg_open_excl(devname, O_RDWR | O_NONBLOCK); + if (f < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", devname); + return (0); + } + usallocal(usalp)->usalfiles[busno][tgt][tlun] = f; + return (1); + } else { + tlun = 0; + for (tgt = 0; tgt < MAX_TGT; tgt++) { + snprintf(devname, sizeof (devname), "/dev/pg%d", tgt); + f = sg_open_excl(devname, O_RDWR | O_NONBLOCK); + if (f < 0) { + /* + * Set up error string but let us clear it later + * if at least one open succeeded. + */ + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '/dev/pg*'"); + if (errno != ENOENT && errno != ENXIO && errno != ENODEV) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", devname); + return (0); + } + } else { + usallocal(usalp)->usalfiles[usallocal(usalp)->pgbus][tgt][tlun] = f; + nopen++; + } + } + } + if (nopen > 0 && usalp->errstr) + usalp->errstr[0] = '\0'; + +openbydev: + if (device != NULL && *device != '\0') { + char *p; + + if (tlun < 0) + return (0); + f = open(device, O_RDWR | O_NONBLOCK); +/* if (f < 0 && errno == ENOENT) {*/ + if (f < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", + device); + return (0); + } + + p = device + strlen(device) -1; + tgt = *p - '0'; + if (tgt < 0 || tgt > 9) + return (0); + usallocal(usalp)->usalfiles[usallocal(usalp)->pgbus][tgt][tlun] = f; + usal_settarget(usalp, usallocal(usalp)->pgbus, tgt, tlun); + + return (++nopen); + } + return (nopen); +} + +static int +usalo_close(SCSI *usalp) +{ + register int f; + register int b; + register int t; + register int l; + + if (usalp->local == NULL) + return (-1); + if (usallocal(usalp)->pgbus < 0) + return (0); + b = usallocal(usalp)->pgbus; + usallocal(usalp)->buscookies[b] = (short)-1; + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + f = usallocal(usalp)->usalfiles[b][t][l]; + if (f >= 0) + close(f); + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + return (PG_MAX_DATA); +} + +#ifdef USE_PG_ONLY + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + char *ret; + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + ret = valloc((size_t)(amt+getpagesize())); + if (ret == NULL) + return (ret); + usalp->bufbase = ret; + ret += getpagesize(); + usallocal(usalp)->SCSIbuf = ret; + return ((void *)ret); + +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + 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); + + if (usalp->local == NULL) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if (usallocal(usalp)->usalfiles[busno][t][l] >= 0) + return (TRUE); + } + return (FALSE); +} + +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); + + if (usalp->local == NULL) + return (-1); + + return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]); +} +#endif /* USE_PG_ONLY */ + +static int +usalo_initiator_id(SCSI *usalp) +{ + return (-1); +} + +static int +usalo_isatapi(SCSI *usalp) +{ + return (TRUE); +} + +static int +usalo_reset(SCSI *usalp, int what) +{ + struct pg_write_hdr hdr = {PG_MAGIC, PG_RESET, 0}; + + if (what == SCG_RESET_NOP) + return (0); + if (what != SCG_RESET_BUS) { + errno = EINVAL; + return (-1); + } + /* + * XXX Does this reset TGT or BUS ??? + */ + return (write(usalp->fd, (char *)&hdr, sizeof (hdr))); + +} + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a):(b)) +#endif + +#define RHSIZE sizeof (struct pg_read_hdr) +#define WHSIZE sizeof (struct pg_write_hdr) +#define LEAD MAX(RHSIZE, WHSIZE) + +static int +do_usal_cmd(SCSI *usalp, struct usal_cmd *sp) +{ + + char local[LEAD+PG_MAX_DATA]; + int use_local, i, r; + int inward = (sp->flags & SCG_RECV_DATA); + + struct pg_write_hdr *whp; + struct pg_read_hdr *rhp; + char *dbp; + + if (sp->cdb_len > 12) + comerrno(EX_BAD, "Can't do %d byte command.\n", sp->cdb_len); + + if (sp->addr == usallocal(usalp)->SCSIbuf) { + use_local = 0; + dbp = sp->addr; + } else { + use_local = 1; + dbp = &local[LEAD]; + if (!inward) + movebytes(sp->addr, dbp, sp->size); + } + + whp = (struct pg_write_hdr *)(dbp - WHSIZE); + rhp = (struct pg_read_hdr *)(dbp - RHSIZE); + + whp->magic = PG_MAGIC; + whp->func = PG_COMMAND; + whp->dlen = sp->size; + whp->timeout = sp->timeout; + + for (i = 0; i < 12; i++) { + if (i < sp->cdb_len) + whp->packet[i] = sp->cdb.cmd_cdb[i]; + else + whp->packet[i] = 0; + } + + i = WHSIZE; + if (!inward) + i += sp->size; + + r = write(usalp->fd, (char *)whp, i); + + if (r < 0) { /* command was not sent */ + sp->ux_errno = geterrno(); + if (sp->ux_errno == ETIME) { + /* + * If the previous command timed out, we cannot send + * any further command until the command in the drive + * is ready. So we behave as if the drive did not + * respond to the command. + */ + sp->error = SCG_FATAL; + return (0); + } + return (-1); + } + + if (r != i) + errmsg("usalo_send(%s) wrote %d bytes (expected %d).\n", + usalp->cmdname, r, i); + + sp->ux_errno = 0; + sp->sense_count = 0; + + r = read(usalp->fd, (char *)rhp, RHSIZE+sp->size); + + if (r < 0) { + sp->ux_errno = geterrno(); + if (sp->ux_errno == ETIME) { + sp->error = SCG_TIMEOUT; + return (0); + } + sp->error = SCG_FATAL; + return (-1); + } + + i = rhp->dlen; + if (i > sp->size) { + /* + * "DMA overrun" should be handled in the kernel. + * However this may happen with flaky PP adapters. + */ + errmsgno(EX_BAD, + "DMA (read) overrun by %d bytes (requested %d bytes).\n", + i - sp->size, sp->size); + sp->resid = sp->size - i; + sp->error = SCG_RETRYABLE; + i = sp->size; + } else { + sp->resid = sp->size - i; + } + + if (use_local && inward) + movebytes(dbp, sp->addr, i); + + fillbytes(&sp->scb, sizeof (sp->scb), '\0'); + fillbytes(&sp->u_sense.cmd_sense, sizeof (sp->u_sense.cmd_sense), '\0'); + + sp->error = SCG_NO_ERROR; + i = rhp->scsi?2:0; +/* i = rhp->scsi;*/ + sp->u_scb.cmd_scb[0] = i; + if (i & 2) { + if (sp->ux_errno == 0) + sp->ux_errno = EIO; + /* + * If there is no DMA overrun and there is a + * SCSI Status byte != 0 then the SCSI cdb transport was OK + * and sp->error must be SCG_NO_ERROR. + */ +/* sp->error = SCG_RETRYABLE;*/ + } + + return (0); + +} + +static int +do_usal_sense(SCSI *usalp, struct usal_cmd *sp) +{ + int ret; + struct usal_cmd s_cmd; + + fillbytes((caddr_t)&s_cmd, sizeof (s_cmd), '\0'); + s_cmd.addr = (caddr_t)sp->u_sense.cmd_sense; + s_cmd.size = sp->sense_len; + s_cmd.flags = SCG_RECV_DATA|SCG_DISRE_ENA; + s_cmd.cdb_len = SC_G0_CDBLEN; + s_cmd.sense_len = CCS_SENSE_LEN; + s_cmd.cdb.g0_cdb.cmd = SC_REQUEST_SENSE; + s_cmd.cdb.g0_cdb.lun = sp->cdb.g0_cdb.lun; + s_cmd.cdb.g0_cdb.count = sp->sense_len; + ret = do_usal_cmd(usalp, &s_cmd); + + if (ret < 0) + return (ret); + + sp->sense_count = sp->sense_len - s_cmd.resid; + return (ret); +} + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + int ret; + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + ret = do_usal_cmd(usalp, sp); + if (ret < 0) + return (ret); + if (sp->u_scb.cmd_scb[0] & 2) + ret = do_usal_sense(usalp, sp); + return (ret); +} + +/* end of scsi-linux-pg.c */ + +#ifndef USE_PG_ONLY + +#undef usalo_version +#undef usalo_help +#undef usalo_open +#undef usalo_close +#undef usalo_send +#undef usalo_maxdma +#undef usalo_initiator_id +#undef usalo_isatapi +#undef usalo_reset + +#endif diff --git a/libusal/scsi-linux-sg.c b/libusal/scsi-linux-sg.c new file mode 100644 index 0000000..81d33d4 --- /dev/null +++ b/libusal/scsi-linux-sg.c @@ -0,0 +1,1754 @@ +/* + * 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-linux-sg.c 1.86 05/11/22 Copyright 1997 J. Schilling */ +/* + * Interface for Linux generic SCSI implementation (sg). + * + * This is the interface for the broken Linux SCSI generic driver. + * This is a hack, that tries to emulate the functionality + * of the usal driver. + * + * Design flaws of the sg driver: + * - cannot see if SCSI command could not be send + * - cannot get SCSI status byte + * - cannot get real dma count of tranfer + * - cannot get number of bytes valid in auto sense data + * - to few data in auto sense (CCS/SCSI-2/SCSI-3 needs >= 18) + * + * This code contains support for the sg driver version 2 by + * H. Eißfeld & J. Schilling + * Although this enhanced version has been announced to Linus and Alan, + * there was no reaction at all. + * + * About half a year later there occured a version in the official + * Linux that was also called version 2. The interface of this version + * looks like a playground - the enhancements from this version are + * more or less useless for a portable real-world program. + * + * With Linux 2.4 the official version of the sg driver is called 3.x + * and seems to be usable again. The main problem now is the curious + * interface that is provided to raise the DMA limit from 32 kB to a + * more reasonable value. To do this in a reliable way, a lot of actions + * are required. + * + * 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. + * + * Copyright (c) 1997 J. Schilling + */ +/* + * 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. + */ + +#include <linux/version.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/utsname.h> + +#ifndef LINUX_VERSION_CODE /* Very old kernel? */ +# define LINUX_VERSION_CODE 0 +#endif + +#if LINUX_VERSION_CODE >= 0x01031a /* <linux/scsi.h> introduced in 1.3.26 */ +#if LINUX_VERSION_CODE >= 0x020000 /* <scsi/scsi.h> introduced somewhere. */ +/* Need to fine tune the ifdef so we get the transition point right. */ +#include <scsi/scsi.h> +#else +#include <linux/scsi.h> +#endif +#else /* LINUX_VERSION_CODE == 0 Very old kernel? */ +#define __KERNEL__ /* Some Linux Include files are inconsistent */ +#include <linux/fs.h> /* From ancient versions, really needed? */ +#undef __KERNEL__ +#include "block/blk.h" /* From ancient versions, really needed? */ +#include "scsi/scsi.h" +#endif + +#if defined(HAVE_BROKEN_SCSI_SG_H) || \ + defined(HAVE_BROKEN_SRC_SCSI_SG_H) +/* + * Be very careful in case that the Linux Kernel maintainers + * unexpectedly fix the bugs in the Linux Lernel include files. + * Only introduce the attempt for a workaround in case the include + * files are broken anyway. + */ +#define __user +#endif +#include "scsi/sg.h" +#if defined(HAVE_BROKEN_SCSI_SG_H) || \ + defined(HAVE_BROKEN_SRC_SCSI_SG_H) +#undef __user +#endif + +#undef sense /* conflict in struct cdrom_generic_command */ +#include <linux/cdrom.h> + +#if defined(CDROM_PACKET_SIZE) && defined(CDROM_SEND_PACKET) +#define USE_OLD_ATAPI +#endif + +#include <glob.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-linux-sg.c-1.86"; /* The version for this transport*/ + +#ifndef SCSI_IOCTL_GET_BUS_NUMBER +#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386 +#endif + +/* + * XXX There must be a better way than duplicating things from system include + * XXX files. This is stolen from /usr/src/linux/drivers/scsi/scsi.h + */ +#ifndef DID_OK +#define DID_OK 0x00 /* NO error */ +#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ +#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ +#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ +#define DID_BAD_TARGET 0x04 /* BAD target. */ +#define DID_ABORT 0x05 /* Told to abort for some other reason */ +#define DID_PARITY 0x06 /* Parity error */ +#define DID_ERROR 0x07 /* Internal error */ +#define DID_RESET 0x08 /* Reset by somebody. */ +#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ +#endif + +/* + * These indicate the error that occurred, and what is available. + */ +#ifndef DRIVER_BUSY +#define DRIVER_BUSY 0x01 +#define DRIVER_SOFT 0x02 +#define DRIVER_MEDIA 0x03 +#define DRIVER_ERROR 0x04 + +#define DRIVER_INVALID 0x05 +#define DRIVER_TIMEOUT 0x06 +#define DRIVER_HARD 0x07 +#define DRIVER_SENSE 0x08 +#endif + +/* + * XXX Should add extra space in buscookies and usalfiles for a "PP bus" + * XXX and for two or more "ATAPI busses". + */ +#define MAX_SCG 1256 /* Max # of SCSI controllers */ +#define MAX_TGT 16 +#define MAX_LUN 8 + +#ifdef USE_OLD_ATAPI +/* + * # of virtual buses (schilly_host number) + */ +#define MAX_SCHILLY_HOSTS MAX_SCG +typedef struct { + Uchar typ:4; + Uchar bus:4; + Uchar host:8; +} ata_buscookies; +#endif + +struct usal_local { + int usalfile; /* Used for SG_GET_BUFSIZE ioctl()*/ + short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN]; + char *filenames[MAX_SCG][MAX_TGT][MAX_LUN]; + short buscookies[MAX_SCG]; + int pgbus; + int pack_id; /* Should be a random number */ + int drvers; + short isold; + short flags; + long xbufsize; + char *xbuf; + char *SCSIbuf; +#ifdef USE_OLD_ATAPI + ata_buscookies bc[MAX_SCHILLY_HOSTS]; +#endif +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +/* + * Flag definitions + */ + +#ifdef SG_BIG_BUFF +#define MAX_DMA_LINUX SG_BIG_BUFF /* Defined in include/scsi/sg.h */ +#else +#define MAX_DMA_LINUX (4*1024) /* Old Linux versions */ +#endif + +#ifndef SG_MAX_SENSE +# define SG_MAX_SENSE 16 /* Too small for CCS / SCSI-2 */ +#endif /* But cannot be changed */ + +#if !defined(__i386) && !defined(i386) && !defined(mc68000) +#define MISALIGN +#endif +/*#define MISALIGN*/ +/*#undef SG_GET_BUFSIZE*/ + + +#ifdef MISALIGN +static int sg_getint(int *ip); +#endif +static int usalo_send(SCSI *usalp); +#ifdef SG_IO +static int sg_rwsend(SCSI *usalp); +#endif +static void sg_clearnblock(int f); +static BOOL sg_setup(SCSI *usalp, int f, int busno, int tgt, int tlun, + int ataidx, char *origname); +static void sg_initdev(SCSI *usalp, int f); +static int sg_mapbus(SCSI *usalp, int busno, int ino); +static BOOL sg_mapdev(SCSI *usalp, int f, int *busp, int *tgtp, int *lunp, + int *chanp, int *inop, int ataidx); +#if defined(SG_SET_RESERVED_SIZE) && defined(SG_GET_RESERVED_SIZE) +static long sg_raisedma(SCSI *usalp, long newmax); +#endif +static void sg_settimeout(int f, int timeout); + +int sg_open_excl(char *device, int mode, BOOL beQuiet); + +static BOOL get_max_secs(char *dirpath, int *outval); + +#if defined(USE_PG) && !defined(USE_PG_ONLY) +#include "scsi-linux-pg.c" +#endif +#ifdef USE_OLD_ATAPI +#include "scsi-linux-ata.c" +#endif + +BOOL check_linux_26() { + int gen, tmp; + struct utsname buf; + return ( 0==uname( &buf ) && sscanf(buf.release, "%d.%d", &gen, &tmp)>1 && tmp>=6); +} + +int sg_open_excl(char *device, int mode, BOOL beQuiet) +{ + int f; + int i=0; + long interval = beQuiet ? 400000 : 1000000; + + f = open(device, mode|O_EXCL); + /* try to reopen locked/busy devices up to five times */ + for (i = 0; (i < 5) && (f == -1 && errno == EBUSY); i++) { + if(!beQuiet) + fprintf(stderr, "Error trying to open %s exclusively (%s)... %s\n", + device, strerror(errno), + (i<4)?"retrying in 1 second.":"giving up."); + usleep(interval + interval * rand()/(RAND_MAX+1.0)); + f = open(device, mode|O_EXCL); + } + if(i==5 && !beQuiet) { + FILE *g = fopen("/proc/mounts", "r"); + if(g) { + char buf[80]; + unsigned int len=strlen(device); + while(!feof(g) && !ferror(g)) { + if(fgets(buf, 79, g) && 0==strncmp(device, buf, len)) { + fprintf(stderr, "WARNING: %s seems to be mounted!\n", device); + } + } + fclose(g); + } + } + return f; +} + +#if 0 +// Dead code, that sysfs parts may become deprecated soon +void map_sg_to_block(char *device, int len) { + char globpat[100]; + glob_t globbuf; + snprintf(globpat, 100, "/sys/class/scsi_generic/%s/device/block:*", device+5); + memset(&globbuf, 0, sizeof(glob_t)); + if(0==glob(globpat, GLOB_DOOFFS | GLOB_NOSORT, NULL, &globbuf)) { + char *p = strrchr(globbuf.gl_pathv[0], ':'); + if(p) snprintf(device, len, "/dev/%s", p+1); + } + globfree(&globbuf); +} +#endif + +/* + * 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) { +#ifdef USE_PG +#error pg-junk + /* + * If we only have a Parallel port or only opened a handle + * for PP, just return PP version. + */ + if (usallocal(usalp)->pgbus == 0 || + (usal_scsibus(usalp) >= 0 && + usal_scsibus(usalp) == usallocal(usalp)->pgbus)) + return (pg_version(usalp, what)); +#endif + 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); + case SCG_KVERSION: + { + static char kv[16]; + int n; + + if (usallocal(usalp)->drvers >= 0) { + n = usallocal(usalp)->drvers; + snprintf(kv, sizeof (kv), + "%d.%d.%d", + n/10000, (n%10000)/100, n%100); + + return (kv); + } + } + } + } + return ((char *)0); +} + +static int +usalo_help(SCSI *usalp, FILE *f) +{ + __usal_help(f, "sg", "Generic transport independent SCSI", + "", "bus,target,lun", "1,2,0", TRUE, FALSE); +#ifdef USE_PG + pg_help(usalp, f); +#endif +#ifdef USE_OLD_ATAPI + usalo_ahelp(usalp, f); +#endif + __usal_help(f, "ATA", "ATA Packet specific SCSI transport using sg interface", + "ATA:", "bus,target,lun", "1,2,0", TRUE, FALSE); + return (0); +} + +#define in_scanmode (busno < 0 && tgt < 0 && tlun < 0) + +/* + * b/t/l is chopped of the device string. + */ +static int +usalo_open(SCSI *usalp, char *device) +{ + int busno = usal_scsibus(usalp); + int tgt = usal_target(usalp); + int tlun = usal_lun(usalp); + register int f; + register int i; + register int b; + register int t; + register int l; + register int nopen = 0; + char devname[64]; + int fake_atabus=0; + + 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); + } + + struct stat statbuf; + if(check_linux_26() && 0!=stat("/sys/kernel", &statbuf)) { + static int warn_sysfs=1; + if(warn_sysfs) { + warn_sysfs=0; + fprintf(stderr, "\nWarning, sysfs is not mounted on /sys!\n" + "It is recommended to mount sysfs to allow better device configuration\n"); + sleep(5); + } + } + + if (device != NULL && *device != '\0') { + fake_atabus=0; + if(0==strncmp(device, "OLDATAPI", 8)) { + device+=3; + usalp->ops = &ata_ops; + return (SCGO_OPEN(usalp, device)); + } + else if(0==strncmp(device, "ATAPI", 5)) { + if(check_linux_26()) { + device+=5; + fake_atabus=1; + fprintf(stderr, "WARNING: the ATAPI: method is considered deprecated on modern kernels!\n" + "Mapping device specification to ATA: method now.\n" + "To force the old ATAPI: method, replace ATAPI: with OLDATAPI:\n"); + } + else { + usalp->ops = &ata_ops; + return (SCGO_OPEN(usalp, device)); + } + } + else if(0==strncmp(device, "ATA", 3)) { + fprintf(stderr, "WARNING: the ATA: method is considered deprecated on modern kernels!\n" + "Use --devices to display the native names.\n"); + fake_atabus=1; + device+=3; + } + if(device[0]==':') + device++; + + } + else if( ! in_scanmode ) { + fprintf(stderr, "WARNING: the deprecated pseudo SCSI syntax found as device specification.\n" + "Support for that may cease in the future versions of wodim. For now,\n" + "the device will be mapped to a block device file where possible.\n" + "Run \"wodim --devices\" for details.\n" ); + sleep(5); + } + + if (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + + usallocal(usalp)->usalfile = -1; + usallocal(usalp)->pgbus = -2; + usallocal(usalp)->SCSIbuf = (char *)-1; + usallocal(usalp)->pack_id = 5; + usallocal(usalp)->drvers = -1; + usallocal(usalp)->isold = -1; + usallocal(usalp)->flags = 0; + usallocal(usalp)->xbufsize = 0L; + usallocal(usalp)->xbuf = NULL; + + for (b = 0; b < MAX_SCG; b++) { + usallocal(usalp)->buscookies[b] = (short)-1; + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + usallocal(usalp)->filenames[b][t][l] = NULL; + } + } + } + } + + if (device != NULL && *device != '\0') + { + /* open ONE directly */ + b = -1; + if (device && strncmp(device, "/dev/hd", 7) == 0 && device[8]=='\0') { + b = device[7] - 'a'; + if (b < 0 || b > 25) + b = -1; + } + if(b>=0 && fake_atabus) + b+=1000; + + f = sg_open_excl(device, O_RDWR | O_NONBLOCK, FALSE); + + if (f < 0) { + /* + * The pg driver has the same rules to decide whether + * to use openbydev. If we cannot open the device, it + * makes no sense to try the /dev/pg* driver. + */ + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", + device); + return (0); + } + sg_clearnblock(f); + /* get some fake SCSI data */ + sg_mapdev(usalp, f, &busno, &tgt, &tlun, 0, 0, b); + usal_settarget(usalp, busno, tgt, tlun); + if (sg_setup(usalp, f, busno, tgt, tlun, b, device)) + return (++nopen); + } + else { + /* scan and maybe keep one open, sg_setup decides */ +#define HDX 0 +#define SCD 1 +#define SG 2 + int h; +/* +retry_scan_open: +*/ + for(h=HDX; h <= (fake_atabus ? HDX : SG) ; h++) { + char *pattern = NULL; + unsigned int first = 0, last = 0; + switch(h) { + case(HDX): + { + pattern="/dev/hd%c"; + first='a'; + last='z'; + break; + } + case(SCD): + { + if(!check_linux_26()) + continue; + pattern="/dev/scd%d"; + first=0; + last=255; + break; + } + case(SG): + { + if(check_linux_26()) + continue; +#if 0 + /* + * Don't touch it on 2.6 until we have a proper locking scheme + */ + if(nopen<=0) + fprintf(stderr, "Warning, using /dev/sg* for SG_IO operation. This method is considered harmful.\n"); + else if(found_scd) + continue; +#endif + pattern="/dev/sg%d"; + first=0; + last=255; + break; + } + } + for(i=first; i<=last; i++) { + snprintf(devname, sizeof (devname), pattern, i); + f = sg_open_excl(devname, O_RDWR | O_NONBLOCK, in_scanmode); + if (f < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", devname); + } else { + if(h == HDX) { // double-check the capabilities on ATAPI devices + int iparm; + + if (ioctl(f, SG_GET_TIMEOUT, &iparm) < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "SCSI unsupported with '%s'", devname); + close(f); + continue; + } + } + sg_clearnblock(f); /* Be very proper about this */ + + /* construct the fake bus number hint, keep it readable */ + b=-1; + if(h==HDX) { + b=i-'a'; + if(!fake_atabus) + b+=1000; + } + + /* sg_setup returns false in scan mode, true if one single target was specified and opened */ + if (sg_setup(usalp, f, busno, tgt, tlun, b, devname)) + return (++nopen); + + if (in_scanmode) + nopen++; + } + } + + if (nopen > 0 && usalp->errstr) + usalp->errstr[0] = '\0'; + + /* that's crap, should not be reached in non-scan mode. + * Let's see whether it can be mapped to an atapi + * device to emulate some old cludge's behaviour. + if(!in_scanmode && busno < 1000 && busno >=0) { + fake_atabus=1; + fprintf(stderr, "Unable to open this SCSI ID. Trying to map to old ATA syntax." + "This workaround will disappear in the near future. Fix your configuration."); + goto retry_scan_open; + } + */ + } + } + + if (usalp->debug > 0) for (b = 0; b < MAX_SCG; b++) { + fprintf((FILE *)usalp->errfile, + "Bus: %d cookie: %X\n", + b, usallocal(usalp)->buscookies[b]); + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + if (usallocal(usalp)->usalfiles[b][t][l] != (short)-1) { + fprintf((FILE *)usalp->errfile, + "file (%d,%d,%d): %d\n", + b, t, l, usallocal(usalp)->usalfiles[b][t][l]); + } + } + } + } + + return (nopen); +} + +static int +usalo_close(SCSI *usalp) +{ + register int f; + register int b; + register int t; + register int l; + + if (usalp->local == NULL) + return (-1); + + for (b = 0; b < MAX_SCG; b++) { + if (b == usallocal(usalp)->pgbus) + continue; + usallocal(usalp)->buscookies[b] = (short)-1; + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + f = usallocal(usalp)->usalfiles[b][t][l]; + if (f >= 0) + close(f); + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + if(usallocal(usalp)->filenames[b][t][l]) { + free(usallocal(usalp)->filenames[b][t][l]); + usallocal(usalp)->filenames[b][t][l]=NULL; + } + } + } + } + if (usallocal(usalp)->xbuf != NULL) { + free(usallocal(usalp)->xbuf); + usallocal(usalp)->xbufsize = 0L; + usallocal(usalp)->xbuf = NULL; + } +#ifdef USE_PG + pg_close(usalp); +#endif + return (0); +} + +/* + * The Linux kernel becomes more and more unmaintainable. + * Every year, a new incompatible SCSI transport interface is added. + * Each of them has it's own contradictory constraints. + * While you cannot have O_NONBLOCK set during operation, at least one + * of the drivers requires O_NONBLOCK to be set during open(). + * This is used to clear O_NONBLOCK immediately after open() succeeded. + */ +static void +sg_clearnblock(int f) +{ + int n; + + n = fcntl(f, F_GETFL); + n &= ~O_NONBLOCK; + fcntl(f, F_SETFL, n); +} + +/*! + * + * Return: TRUE when single target is chosen and was opened successfully, FALSE otherwise (on scans, etc). + */ + +static BOOL +sg_setup(SCSI *usalp, int f, int busno, int tgt, int tlun, int ataidx, char *origname) +{ + int n; + int Chan; + int Ino; + int Bus; + int Target; + int Lun; + BOOL onetarget = FALSE; + +#ifdef SG_GET_VERSION_NUM + if (usallocal(usalp)->drvers < 0) { + usallocal(usalp)->drvers = 0; + if (ioctl(f, SG_GET_VERSION_NUM, &n) >= 0) { + usallocal(usalp)->drvers = n; + if (usalp->overbose) { + fprintf((FILE *)usalp->errfile, + "Linux sg driver version: %d.%d.%d\n", + n/10000, (n%10000)/100, n%100); + } + } + } +#endif + if (usal_scsibus(usalp) >= 0 && usal_target(usalp) >= 0 && usal_lun(usalp) >= 0) + onetarget = TRUE; + + sg_mapdev(usalp, f, &Bus, &Target, &Lun, &Chan, &Ino, ataidx); + /* + * For old kernels try to make the best guess. + */ + Ino |= Chan << 8; + n = sg_mapbus(usalp, Bus, Ino); + if (Bus == -1) { + Bus = n; + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "SCSI Bus: %d (mapped from %d)\n", Bus, Ino); + } + } + + if (Bus < 0 || Bus >= MAX_SCG || Target < 0 || Target >= MAX_TGT || + Lun < 0 || Lun >= MAX_LUN) { + return (FALSE); + } + + if (usallocal(usalp)->usalfiles[Bus][Target][Lun] == (short)-1) + usallocal(usalp)->usalfiles[Bus][Target][Lun] = (short)f; + + if (usallocal(usalp)->filenames[Bus][Target][Lun] == NULL) + usallocal(usalp)->filenames[Bus][Target][Lun] = strdup(origname); + + if (onetarget) { + if (Bus == busno && Target == tgt && Lun == tlun) { + sg_initdev(usalp, f); + usallocal(usalp)->usalfile = f; /* remember file for ioctl's */ + return (TRUE); + } else { + usallocal(usalp)->usalfiles[Bus][Target][Lun] = (short)-1; + close(f); + } + } else { + /* + * SCSI bus scanning may cause other generic SCSI activities to + * fail because we set the default timeout and clear command + * queues (in case of the old sg driver interface). + */ + sg_initdev(usalp, f); + if (usallocal(usalp)->usalfile < 0) + usallocal(usalp)->usalfile = f; /* remember file for ioctl's */ + } + return (FALSE); +} + +static void +sg_initdev(SCSI *usalp, int f) +{ + struct sg_rep { + struct sg_header hd; + unsigned char rbuf[100]; + } sg_rep; + int n; + int i; + struct stat sb; + + sg_settimeout(f, usalp->deftimeout); + + /* + * If it's a block device, don't read.... pre Linux-2.4 /dev/sg* + * definitely is a character device and we only need to clear the + * queue for old /dev/sg* versions. If somebody ever implements + * raw disk access for Linux, this test may fail. + */ + if (fstat(f, &sb) >= 0 && S_ISBLK(sb.st_mode)) + return; + + /* Eat any unwanted garbage from prior use of this device */ + + n = fcntl(f, F_GETFL); /* Be very proper about this */ + fcntl(f, F_SETFL, n|O_NONBLOCK); + + fillbytes((caddr_t)&sg_rep, sizeof (struct sg_header), '\0'); + sg_rep.hd.reply_len = sizeof (struct sg_header); + + /* + * This is really ugly. + * We come here if 'f' is related to a raw device. If Linux + * will ever have raw devices for /dev/hd* we may get problems. + * As long as there is no clean way to find out whether the + * filedescriptor 'f' is related to an old /dev/sg* or to + * /dev/hd*, we must assume that we found an old /dev/sg* and + * clean it up. Unfortunately, reading from /dev/hd* will + * Access the medium. + */ + for (i = 0; i < 1000; i++) { /* Read at least 32k from /dev/sg* */ + int ret; + + ret = read(f, &sg_rep, sizeof (struct sg_rep)); + if (ret > 0) + continue; + if (ret == 0 || errno == EAGAIN || errno == EIO) + break; + if (ret < 0 && i > 10) /* Stop on repeated unknown error */ + break; + } + fcntl(f, F_SETFL, n); +} + +static int +sg_mapbus(SCSI *usalp, int busno, int ino) +{ + register int i; + + if (busno >= 0 && busno < MAX_SCG) { + /* + * SCSI_IOCTL_GET_BUS_NUMBER worked. + * Now we have the problem that Linux does not properly number + * SCSI busses. The Bus number that Linux creates really is + * the controller (card) number. I case of multi SCSI bus + * cards we are lost. + */ + if (usallocal(usalp)->buscookies[busno] == (short)-1) { + usallocal(usalp)->buscookies[busno] = ino; + return (busno); + } + /* + * if (usallocal(usalp)->buscookies[busno] != (short)ino) + errmsgno(EX_BAD, "Warning Linux Bus mapping botch.\n"); + */ + return (busno); + + } else for (i = 0; i < MAX_SCG; i++) { + if (usallocal(usalp)->buscookies[i] == (short)-1) { + usallocal(usalp)->buscookies[i] = ino; + return (i); + } + + if (usallocal(usalp)->buscookies[i] == ino) + return (i); + } + return (0); +} + +static BOOL +sg_mapdev(SCSI *usalp, int f, int *busp, int *tgtp, int *lunp, int *chanp, + int *inop, int ataidx) +{ + struct sg_id { + long l1; /* target | lun << 8 | channel << 16 | low_ino << 24 */ + long l2; /* Unique id */ + } sg_id; + int Chan; + int Ino; + int Bus; + int Target; + int Lun; + + if (ataidx >= 0) { + /* + * The badly designed /dev/hd* interface maps everything + * to 0,0,0 so we need to do the mapping ourselves. + */ + *busp = (ataidx/1000) * 1000; + *tgtp = ataidx%1000; + *lunp = 0; + if (chanp) + *chanp = 0; + if (inop) + *inop = 0; + return (TRUE); + } + if (ioctl(f, SCSI_IOCTL_GET_IDLUN, &sg_id)) + return (FALSE); + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "l1: 0x%lX l2: 0x%lX\n", sg_id.l1, sg_id.l2); + } + if (ioctl(f, SCSI_IOCTL_GET_BUS_NUMBER, &Bus) < 0) { + Bus = -1; + } + + Target = sg_id.l1 & 0xFF; + Lun = (sg_id.l1 >> 8) & 0xFF; + Chan = (sg_id.l1 >> 16) & 0xFF; + Ino = (sg_id.l1 >> 24) & 0xFF; + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Bus: %d Target: %d Lun: %d Chan: %d Ino: %d\n", + Bus, Target, Lun, Chan, Ino); + } + *busp = Bus; + *tgtp = Target; + *lunp = Lun; + if (chanp) + *chanp = Chan; + if (inop) + *inop = Ino; + return (TRUE); +} + +#if defined(SG_SET_RESERVED_SIZE) && defined(SG_GET_RESERVED_SIZE) +/* + * The way Linux does DMA resouce management is a bit curious. + * It totally deviates from all other OS and forces long ugly code. + * If we are opening all drivers for a SCSI bus scan operation, we need + * to set the limit for all open devices. + * This may use up all kernel memory ... so do the job carefully. + * + * A big problem is that SG_SET_RESERVED_SIZE does not return any hint + * on whether the request did fail. The only way to find if it worked + * is to use SG_GET_RESERVED_SIZE to read back the current values. + */ +static long +sg_raisedma(SCSI *usalp, long newmax) +{ + register int b; + register int t; + register int l; + register int f; + int val; + int old; + + /* + * First try to raise the DMA limit to a moderate value that + * most likely does not use up all kernel memory. + */ + val = 126*1024; + + if (val > MAX_DMA_LINUX) { + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + if ((f = SCGO_FILENO(usalp, b, t, l)) < 0) + continue; + old = 0; + if (ioctl(f, SG_GET_RESERVED_SIZE, &old) < 0) + continue; + if (val > old) + ioctl(f, SG_SET_RESERVED_SIZE, &val); + } + } + } + } + + /* + * Now to raise the DMA limit to what we really need. + */ + if (newmax > val) { + val = newmax; + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + if ((f = SCGO_FILENO(usalp, b, t, l)) < 0) + continue; + old = 0; + if (ioctl(f, SG_GET_RESERVED_SIZE, &old) < 0) + continue; + if (val > old) + ioctl(f, SG_SET_RESERVED_SIZE, &val); + } + } + } + } + + /* + * To make sure we did not fail (the ioctl does not report errors) + * we need to check the DMA limits. We return the smallest value. + */ + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + if ((f = SCGO_FILENO(usalp, b, t, l)) < 0) + continue; + if (ioctl(f, SG_GET_RESERVED_SIZE, &val) < 0) + continue; + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Target (%d,%d,%d): DMA max %d old max: %ld\n", + b, t, l, val, newmax); + } + if (val < newmax) + newmax = val; + } + } + } + return ((long)newmax); +} +#endif + +static char *freadstring(char *fn, char *out, int len) { + char *ret; + FILE *fd=fopen(fn, "r"); + out[0]='\0'; + if(!fd) return NULL; + ret = fgets(out, len, fd); + fclose(fd); + return ret; +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + struct stat stbuf; + long maxdma = MAX_DMA_LINUX; + +#if defined(SG_SET_RESERVED_SIZE) && defined(SG_GET_RESERVED_SIZE) + /* + * Use the curious new kernel interface found on Linux >= 2.2.10 + * This interface first appeared in 2.2.6 but it was not working. + */ + if (usallocal(usalp)->drvers >= 20134) + maxdma = sg_raisedma(usalp, amt); +#endif + /* + * First try the modern kernel 2.6.1x way to detect the real maximum + * DMA for this specific device, then try the other methods. + */ + if(0==fstat(usallocal(usalp)->usalfile, &stbuf)) { + /* that's ugly, there are so many symlinks in sysfs but none from + * major:minor to the relevant directory */ + long int major, minor, i; + major=stbuf.st_rdev>>8; + minor=stbuf.st_rdev&0xFF; + if (usalp->debug > 0) + fprintf(stderr, "Looking for data for major:minor: %ld:%ld\n", major, minor); + glob_t globbuf; + memset(&globbuf, 0, sizeof(glob_t)); + /* *dev files contain the major:minor strings to compare */ + glob("/sys/class/scsi_generic/*/device/block*/queue/max_sectors_kb", GLOB_DOOFFS | GLOB_NOSORT, NULL, &globbuf); + glob("/sys/block/*/device/block*/queue/max_sectors_kb", GLOB_DOOFFS | GLOB_NOSORT | GLOB_APPEND, NULL, &globbuf); + for(i=0;i<globbuf.gl_pathc; i++) { + char *cut, *ende; + char buf[64]; + cut=strstr(globbuf.gl_pathv[i], "/device/")+4; + *cut='\0'; + freadstring(globbuf.gl_pathv[i], buf, sizeof(buf)); + if(strtol(buf, &ende, 10) == major && ende && atoi(ende) == minor) { + *cut='i'; + freadstring(globbuf.gl_pathv[i], buf, sizeof(buf)); + return(1024*atoi(buf)); + } + + } + globfree(&globbuf); + } +#ifdef SG_GET_BUFSIZE + /* + * We assume that all /dev/sg instances use the same + * maximum buffer size. + */ + maxdma = ioctl(usallocal(usalp)->usalfile, SG_GET_BUFSIZE, 0); +#endif + if (maxdma < 0) { +#ifdef USE_PG + /* + * If we only have a Parallel port, just return PP maxdma. + */ + if (usallocal(usalp)->pgbus == 0) + return (pg_maxdma(usalp, amt)); +#endif + if (usallocal(usalp)->usalfile >= 0) + maxdma = MAX_DMA_LINUX; + } +#ifdef USE_PG + if (usal_scsibus(usalp) == usallocal(usalp)->pgbus) + return (pg_maxdma(usalp, amt)); + if ((usal_scsibus(usalp) < 0) && (pg_maxdma(usalp, amt) < maxdma)) + return (pg_maxdma(usalp, amt)); +#endif + return (maxdma); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + char *ret; + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + /* + * For performance reason, we allocate pagesize() + * bytes before the SCSI buffer to avoid + * copying the whole buffer contents when + * setting up the /dev/sg data structures. + */ + ret = valloc((size_t)(amt+getpagesize())); + if (ret == NULL) + return (ret); + usalp->bufbase = ret; + ret += getpagesize(); + usallocal(usalp)->SCSIbuf = ret; + return ((void *)ret); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + 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); + + if (usalp->local == NULL) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if (usallocal(usalp)->usalfiles[busno][t][l] >= 0) + return (TRUE); + } + return (FALSE); +} + +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); + + if (usalp->local == NULL) + return (-1); + + return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]); +} + +static int +usalo_initiator_id(SCSI *usalp) +{ +#ifdef USE_PG + if (usal_scsibus(usalp) == usallocal(usalp)->pgbus) + return (pg_initiator_id(usalp)); +#endif + return (-1); +} + +static int +usalo_isatapi(SCSI *usalp) +{ + return -1; +#if 0 + /* + * Who exactly needs this information? Just for some bitching in wodim? + * Is this an _abstraction_ layer or spam layer? + */ +#ifdef USE_PG + if (usal_scsibus(usalp) == usallocal(usalp)->pgbus) + return (pg_isatapi(usalp)); +#endif + + /* + * The /dev/hd* interface always returns TRUE for SG_EMULATED_HOST. + * So this is completely useless. + */ + if (usallocal(usalp)->flags & LF_ATA) + return (-1); + +#ifdef SG_EMULATED_HOST + { + int emulated = FALSE; + + /* + * XXX Should we use this at all? + * XXX The badly designed /dev/hd* interface always + * XXX returns TRUE, even when used with e.g. /dev/sr0. + */ + if (ioctl(usalp->fd, SG_EMULATED_HOST, &emulated) >= 0) + return (emulated != 0); + } +#endif + return (-1); +#endif +} + +static int +usalo_reset(SCSI *usalp, int what) +{ +#ifdef SG_SCSI_RESET + int f = usalp->fd; + int func = -1; +#endif +#ifdef USE_PG + if (usal_scsibus(usalp) == usallocal(usalp)->pgbus) + return (pg_reset(usalp, what)); +#endif + /* + * Do we have a SCSI reset in the Linux sg driver? + */ +#ifdef SG_SCSI_RESET + /* + * Newer Linux sg driver seem to finally implement it... + */ +#ifdef SG_SCSI_RESET_NOTHING + func = SG_SCSI_RESET_NOTHING; + if (ioctl(f, SG_SCSI_RESET, &func) >= 0) { + if (what == SCG_RESET_NOP) + return (0); +#ifdef SG_SCSI_RESET_DEVICE + if (what == SCG_RESET_TGT) { + func = SG_SCSI_RESET_DEVICE; + if (ioctl(f, SG_SCSI_RESET, &func) >= 0) + return (0); + } +#endif +#ifdef SG_SCSI_RESET_BUS + if (what == SCG_RESET_BUS) { + func = SG_SCSI_RESET_BUS; + if (ioctl(f, SG_SCSI_RESET, &func) >= 0) + return (0); + } +#endif + } +#endif +#endif + return (-1); +} + +static void +sg_settimeout(int f, int tmo) +{ +#ifndef HZ + static int HZ=0; + if (!HZ) + HZ = sysconf(_SC_CLK_TCK); +#endif + tmo *= HZ; + if (tmo) + tmo += HZ/2; + + if (ioctl(f, SG_SET_TIMEOUT, &tmo) < 0) + comerr("Cannot set SG_SET_TIMEOUT.\n"); +} + +/* + * Get misaligned int. + * Needed for all recent processors (sparc/ppc/alpha) + * because the /dev/sg design forces us to do misaligned + * reads of integers. + */ +#ifdef MISALIGN +static int +sg_getint(int *ip) +{ + int ret; + register char *cp = (char *)ip; + register char *tp = (char *)&ret; + register int i; + + for (i = sizeof (int); --i >= 0; ) + *tp++ = *cp++; + + return (ret); +} +#define GETINT(a) sg_getint(&(a)) +#else +#define GETINT(a) (a) +#endif + +#ifdef SG_IO +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + int ret; + sg_io_hdr_t sg_io; + struct timeval to; + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + sp->ux_errno = EIO; + return (0); + } + if (usallocal(usalp)->isold > 0) { + return (sg_rwsend(usalp)); + } + fillbytes((caddr_t)&sg_io, sizeof (sg_io), '\0'); + + sg_io.interface_id = 'S'; + + if (sp->flags & SCG_RECV_DATA) { + sg_io.dxfer_direction = SG_DXFER_FROM_DEV; + } else if (sp->size > 0) { + sg_io.dxfer_direction = SG_DXFER_TO_DEV; + } else { + sg_io.dxfer_direction = SG_DXFER_NONE; + } + sg_io.cmd_len = sp->cdb_len; + if (sp->sense_len > SG_MAX_SENSE) + sg_io.mx_sb_len = SG_MAX_SENSE; + else + sg_io.mx_sb_len = sp->sense_len; + sg_io.dxfer_len = sp->size; + sg_io.dxferp = sp->addr; + sg_io.cmdp = sp->cdb.cmd_cdb; + sg_io.sbp = sp->u_sense.cmd_sense; + sg_io.timeout = sp->timeout*1000; + sg_io.flags |= SG_FLAG_DIRECT_IO; + + ret = ioctl(usalp->fd, SG_IO, &sg_io); + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "ioctl ret: %d\n", ret); + } + + if (ret < 0) { + sp->ux_errno = geterrno(); + /* + * Check if SCSI command cound not be send at all. + * Linux usually returns EINVAL for an unknoen ioctl. + * In case somebody from the Linux kernel team learns that the + * corect errno would be ENOTTY, we check for this errno too. + */ + if ((sp->ux_errno == ENOTTY || sp->ux_errno == EINVAL) && + usallocal(usalp)->isold < 0) { + usallocal(usalp)->isold = 1; + return (sg_rwsend(usalp)); + } + if (sp->ux_errno == ENXIO || + sp->ux_errno == EINVAL || sp->ux_errno == EACCES) { + return (-1); + } + } + + sp->u_scb.cmd_scb[0] = sg_io.status; + sp->sense_count = sg_io.sb_len_wr; + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "host_status: %02X driver_status: %02X\n", + sg_io.host_status, sg_io.driver_status); + } + + switch (sg_io.host_status) { + + case DID_OK: + /* + * If there is no DMA overrun and there is a + * SCSI Status byte != 0 then the SCSI cdb transport + * was OK and sp->error must be SCG_NO_ERROR. + */ + if ((sg_io.driver_status & DRIVER_SENSE) != 0) { + if (sp->ux_errno == 0) + sp->ux_errno = EIO; + + if (sp->u_sense.cmd_sense[0] != 0 && + sp->u_scb.cmd_scb[0] == 0) { + /* + * The Linux SCSI system up to 2.4.xx + * trashes the status byte in the + * kernel. This is true at least for + * ide-scsi emulation. Until this gets + * fixed, we need this hack. + */ + sp->u_scb.cmd_scb[0] = ST_CHK_COND; + if (sp->sense_count == 0) + sp->sense_count = SG_MAX_SENSE; + + if ((sp->u_sense.cmd_sense[2] == 0) && + (sp->u_sense.cmd_sense[12] == 0) && + (sp->u_sense.cmd_sense[13] == 0)) { + /* + * The Linux SCSI system will + * send a request sense for + * even a dma underrun error. + * Clear CHECK CONDITION state + * in case of No Sense. + */ + sp->u_scb.cmd_scb[0] = 0; + sp->u_sense.cmd_sense[0] = 0; + sp->sense_count = 0; + } + } + } + break; + + case DID_NO_CONNECT: /* Arbitration won, retry NO_CONNECT? */ + sp->error = SCG_RETRYABLE; + break; + case DID_BAD_TARGET: + sp->error = SCG_FATAL; + break; + + case DID_TIME_OUT: + __usal_times(usalp); + + if (sp->timeout > 1 && usalp->cmdstop->tv_sec == 0) { + sp->u_scb.cmd_scb[0] = 0; + sp->error = SCG_FATAL; /* a selection timeout */ + } else { + sp->error = SCG_TIMEOUT; + } + break; + + default: + to.tv_sec = sp->timeout; + to.tv_usec = 500000; + __usal_times(usalp); + + if (usalp->cmdstop->tv_sec < to.tv_sec || + (usalp->cmdstop->tv_sec == to.tv_sec && + usalp->cmdstop->tv_usec < to.tv_usec)) { + + sp->ux_errno = 0; + sp->error = SCG_TIMEOUT; /* a timeout */ + } else { + sp->error = SCG_RETRYABLE; + } + break; + } + if (sp->error && sp->ux_errno == 0) + sp->ux_errno = EIO; + + sp->resid = sg_io.resid; + return (0); +} +#else +# define sg_rwsend usalo_send +#endif + +static int +sg_rwsend(SCSI *usalp) +{ + int f = usalp->fd; + struct usal_cmd *sp = usalp->scmd; + struct sg_rq *sgp; + struct sg_rq *sgp2; + int i; + int pack_len; + int reply_len; + int amt = sp->cdb_len; + struct sg_rq { + struct sg_header hd; + unsigned char buf[MAX_DMA_LINUX+SCG_MAX_CMD]; + } sg_rq; +#ifdef SG_GET_BUFSIZE /* We may use a 'sg' version 2 driver */ + char driver_byte; + char host_byte; + char msg_byte; + char status_byte; +#endif + + if (f < 0) { + sp->error = SCG_FATAL; + sp->ux_errno = EIO; + return (0); + } +#ifdef USE_PG + if (usal_scsibus(usalp) == usallocal(usalp)->pgbus) + return (pg_send(usalp)); +#endif + if (sp->timeout != usalp->deftimeout) + sg_settimeout(f, sp->timeout); + + + sgp2 = sgp = &sg_rq; + if (sp->addr == usallocal(usalp)->SCSIbuf) { + sgp = (struct sg_rq *) + (usallocal(usalp)->SCSIbuf - (sizeof (struct sg_header) + amt)); + sgp2 = (struct sg_rq *) + (usallocal(usalp)->SCSIbuf - (sizeof (struct sg_header))); + } else { + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "DMA addr: 0x%8.8lX size: %d - using copy buffer\n", + (long)sp->addr, sp->size); + } + if (sp->size > (int)(sizeof (sg_rq.buf) - SCG_MAX_CMD)) { + + if (usallocal(usalp)->xbuf == NULL) { + usallocal(usalp)->xbufsize = usalp->maxbuf; + usallocal(usalp)->xbuf = + malloc(usallocal(usalp)->xbufsize + + SCG_MAX_CMD + + sizeof (struct sg_header)); + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Allocated DMA copy buffer, addr: 0x%8.8lX size: %ld\n", + (long)usallocal(usalp)->xbuf, + usalp->maxbuf); + } + } + if (usallocal(usalp)->xbuf == NULL || + sp->size > usallocal(usalp)->xbufsize) { + errno = ENOMEM; + return (-1); + } + sgp2 = sgp = (struct sg_rq *)usallocal(usalp)->xbuf; + } + } + + /* + * This is done to avoid misaligned access of sgp->some_int + */ + pack_len = sizeof (struct sg_header) + amt; + reply_len = sizeof (struct sg_header); + if (sp->flags & SCG_RECV_DATA) { + reply_len += sp->size; + } else { + pack_len += sp->size; + } + +#ifdef MISALIGN + /* + * sgp->some_int may be misaligned if (sp->addr == SCSIbuf) + * This is no problem on Intel porocessors, however + * all other processors don't like it. + * sizeof (struct sg_header) + amt is usually not a multiple of + * sizeof (int). For this reason, we fill in the values into sg_rq + * which is always corectly aligned and then copy it to the real + * location if this location differs from sg_rq. + * Never read/write directly to sgp->some_int !!!!! + */ + fillbytes((caddr_t)&sg_rq, sizeof (struct sg_header), '\0'); + + sg_rq.hd.pack_len = pack_len; + sg_rq.hd.reply_len = reply_len; + sg_rq.hd.pack_id = usallocal(usalp)->pack_id++; +/* sg_rq.hd.result = 0; not needed because of fillbytes() */ + + if ((caddr_t)&sg_rq != (caddr_t)sgp) + movebytes((caddr_t)&sg_rq, (caddr_t)sgp, sizeof (struct sg_header)); +#else + fillbytes((caddr_t)sgp, sizeof (struct sg_header), '\0'); + + sgp->hd.pack_len = pack_len; + sgp->hd.reply_len = reply_len; + sgp->hd.pack_id = usallocal(usalp)->pack_id++; +/* sgp->hd.result = 0; not needed because of fillbytes() */ +#endif + if (amt == 12) + sgp->hd.twelve_byte = 1; + + + for (i = 0; i < amt; i++) { + sgp->buf[i] = sp->cdb.cmd_cdb[i]; + } + if (!(sp->flags & SCG_RECV_DATA)) { + if ((void *)sp->addr != (void *)&sgp->buf[amt]) + movebytes(sp->addr, &sgp->buf[amt], sp->size); + amt += sp->size; + } +#ifdef SG_GET_BUFSIZE + sgp->hd.want_new = 1; /* Order new behaviour */ + sgp->hd.cdb_len = sp->cdb_len; /* Set CDB length */ + if (sp->sense_len > SG_MAX_SENSE) + sgp->hd.sense_len = SG_MAX_SENSE; + else + sgp->hd.sense_len = sp->sense_len; +#endif + i = sizeof (struct sg_header) + amt; + if ((amt = write(f, sgp, i)) < 0) { /* write */ + sg_settimeout(f, usalp->deftimeout); + return (-1); + } else if (amt != i) { + errmsg("usalo_send(%s) wrote %d bytes (expected %d).\n", + usalp->cmdname, amt, i); + } + + if (sp->addr == usallocal(usalp)->SCSIbuf) { + movebytes(sgp, sgp2, sizeof (struct sg_header)); + sgp = sgp2; + } + sgp->hd.sense_buffer[0] = 0; + if ((amt = read(f, sgp, reply_len)) < 0) { /* read */ + sg_settimeout(f, usalp->deftimeout); + return (-1); + } + + if (sp->flags & SCG_RECV_DATA && ((void *)sgp->buf != (void *)sp->addr)) { + movebytes(sgp->buf, sp->addr, sp->size); + } + sp->ux_errno = GETINT(sgp->hd.result); /* Unaligned read */ + sp->error = SCG_NO_ERROR; + +#ifdef SG_GET_BUFSIZE + if (sgp->hd.grant_new) { + sp->sense_count = sgp->hd.sense_len; + pack_len = GETINT(sgp->hd.sg_cmd_status); /* Unaligned read */ + driver_byte = (pack_len >> 24) & 0xFF; + host_byte = (pack_len >> 16) & 0xFF; + msg_byte = (pack_len >> 8) & 0xFF; + status_byte = pack_len & 0xFF; + + switch (host_byte) { + + case DID_OK: + if ((driver_byte & DRIVER_SENSE || + sgp->hd.sense_buffer[0] != 0) && + status_byte == 0) { + /* + * The Linux SCSI system up to 2.4.xx + * trashes the status byte in the + * kernel. This is true at least for + * ide-scsi emulation. Until this gets + * fixed, we need this hack. + */ + status_byte = ST_CHK_COND; + if (sgp->hd.sense_len == 0) + sgp->hd.sense_len = SG_MAX_SENSE; + + if ((sp->u_sense.cmd_sense[2] == 0) && + (sp->u_sense.cmd_sense[12] == 0) && + (sp->u_sense.cmd_sense[13] == 0)) { + /* + * The Linux SCSI system will + * send a request sense for + * even a dma underrun error. + * Clear CHECK CONDITION state + * in case of No Sense. + */ + sp->u_scb.cmd_scb[0] = 0; + sp->u_sense.cmd_sense[0] = 0; + sp->sense_count = 0; + } + } + break; + + case DID_NO_CONNECT: /* Arbitration won, retry NO_CONNECT? */ + sp->error = SCG_RETRYABLE; + break; + + case DID_BAD_TARGET: + sp->error = SCG_FATAL; + break; + + case DID_TIME_OUT: + sp->error = SCG_TIMEOUT; + break; + + default: + sp->error = SCG_RETRYABLE; + + if ((driver_byte & DRIVER_SENSE || + sgp->hd.sense_buffer[0] != 0) && + status_byte == 0) { + status_byte = ST_CHK_COND; + sp->error = SCG_NO_ERROR; + } + if (status_byte != 0 && sgp->hd.sense_len == 0) { + sgp->hd.sense_len = SG_MAX_SENSE; + sp->error = SCG_NO_ERROR; + } + break; + + } + if ((host_byte != DID_OK || status_byte != 0) && sp->ux_errno == 0) + sp->ux_errno = EIO; + sp->u_scb.cmd_scb[0] = status_byte; + if (status_byte & ST_CHK_COND) { + sp->sense_count = sgp->hd.sense_len; + movebytes(sgp->hd.sense_buffer, sp->u_sense.cmd_sense, sp->sense_count); + } + } else +#endif + { + if (GETINT(sgp->hd.result) == EBUSY) { /* Unaligned read */ + struct timeval to; + + to.tv_sec = sp->timeout; + to.tv_usec = 500000; + __usal_times(usalp); + + if (sp->timeout > 1 && usalp->cmdstop->tv_sec == 0) { + sp->u_scb.cmd_scb[0] = 0; + sp->ux_errno = EIO; + sp->error = SCG_FATAL; /* a selection timeout */ + } else if (usalp->cmdstop->tv_sec < to.tv_sec || + (usalp->cmdstop->tv_sec == to.tv_sec && + usalp->cmdstop->tv_usec < to.tv_usec)) { + + sp->ux_errno = EIO; + sp->error = SCG_TIMEOUT; /* a timeout */ + } else { + sp->error = SCG_RETRYABLE; /* may be BUS_BUSY */ + } + } + + if (sp->flags & SCG_RECV_DATA) + sp->resid = (sp->size + sizeof (struct sg_header)) - amt; + else + sp->resid = 0; /* sg version1 cannot return DMA resid count */ + + if (sgp->hd.sense_buffer[0] != 0) { + sp->scb.chk = 1; + sp->sense_count = SG_MAX_SENSE; + movebytes(sgp->hd.sense_buffer, sp->u_sense.cmd_sense, sp->sense_count); + if (sp->ux_errno == 0) + sp->ux_errno = EIO; + } + } + + if (usalp->verbose > 0 && usalp->debug > 0) { +#ifdef SG_GET_BUFSIZE + fprintf((FILE *)usalp->errfile, + "status: 0x%08X pack_len: %d, reply_len: %d pack_id: %d result: %d wn: %d gn: %d cdb_len: %d sense_len: %d sense[0]: %02X\n", + GETINT(sgp->hd.sg_cmd_status), + GETINT(sgp->hd.pack_len), + GETINT(sgp->hd.reply_len), + GETINT(sgp->hd.pack_id), + GETINT(sgp->hd.result), + sgp->hd.want_new, + sgp->hd.grant_new, + sgp->hd.cdb_len, + sgp->hd.sense_len, + sgp->hd.sense_buffer[0]); +#else + fprintf((FILE *)usalp->errfile, + "pack_len: %d, reply_len: %d pack_id: %d result: %d sense[0]: %02X\n", + GETINT(sgp->hd.pack_len), + GETINT(sgp->hd.reply_len), + GETINT(sgp->hd.pack_id), + GETINT(sgp->hd.result), + sgp->hd.sense_buffer[0]); +#endif +#ifdef DEBUG + fprintf((FILE *)usalp->errfile, "sense: "); + for (i = 0; i < 16; i++) + fprintf((FILE *)usalp->errfile, "%02X ", sgp->hd.sense_buffer[i]); + fprintf((FILE *)usalp->errfile, "\n"); +#endif + } + + if (sp->timeout != usalp->deftimeout) + sg_settimeout(f, usalp->deftimeout); + return (0); +}; + +#define HAVE_NAT_NAMES +static char * usalo_natname(SCSI *usalp, int busno, int tgt, int tlun) { + if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) + return "BADID"; + return usallocal(usalp)->filenames[busno][tgt][tlun]; +} diff --git a/libusal/scsi-mac-iokit.c b/libusal/scsi-mac-iokit.c new file mode 100644 index 0000000..7e5ee4f --- /dev/null +++ b/libusal/scsi-mac-iokit.c @@ -0,0 +1,539 @@ +/* + * 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-mac-iokit.c 1.10 05/05/15 Copyright 1997,2001-2004 J. Schilling */ +/* + * Interface to the Darwin IOKit SCSI drivers + * + * Notes: Uses the IOKit/scsi-commands/SCSITaskLib interface + * + * As of October 2001, this interface does not support SCSI parallel bus + * (old-fashioned SCSI). It does support ATAPI, Firewire, and USB. + * + * First version done by Constantine Sapuntzakis <csapuntz@Stanford.EDU> + * + * 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. + * + * Copyright (c) 1997,2001-2004 J. Schilling + */ +/* + * 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. + */ + +/* + * 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-mac-iokit.c-1.10"; /* The version for this transport */ + +#define MAX_SCG 16 /* Max # of SCSI controllers */ +#define MAX_TGT 16 +#define MAX_LUN 8 + +#include <statdefs.h> +#include <mach/mach.h> +#include <Carbon/Carbon.h> +#include <IOKit/IOKitLib.h> +#include <IOKit/IOCFPlugIn.h> +#include <IOKit/scsi-commands/SCSITaskLib.h> +#include <mach/mach_error.h> + +struct usal_local { + MMCDeviceInterface **mmcDeviceInterface; + SCSITaskDeviceInterface **scsiTaskDeviceInterface; + mach_port_t masterPort; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +#define MAX_DMA_NEXT (32*1024) +#if 0 +#define MAX_DMA_NEXT (64*1024) /* Check if this is not too big */ +#endif + +/* + * 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, "SCSITaskDeviceInterface", "Apple SCSI", + "", "Mac Prom device name", "IOCompactDiscServices/0", + FALSE, FALSE); + return (0); +} + + +/* + * Valid Device names: + * IOCompactDiscServices + * IODVDServices + * IOSCSIPeripheralDeviceNub + * + * Also a / and a number can be appended to refer to something + * more than the first device (e.g. IOCompactDiscServices/5 for the 5th + * compact disc attached) + */ +static int +usalo_open(SCSI *usalp, char *device) +{ + mach_port_t masterPort = NULL; + io_iterator_t scsiObjectIterator = NULL; + IOReturn ioReturnValue = kIOReturnSuccess; + CFMutableDictionaryRef dict = NULL; + io_object_t scsiDevice = NULL; + HRESULT plugInResult; + IOCFPlugInInterface **plugInInterface = NULL; + MMCDeviceInterface **mmcDeviceInterface = NULL; + SCSITaskDeviceInterface **scsiTaskDeviceInterface = NULL; + SInt32 score = 0; + int err = -1; + char *realdevice = NULL, *tmp; + int driveidx = 1, idx = 1; + + if (device == NULL) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Please specify a device name (e.g. IOCompactDiscServices/0)"); + goto out; + } + + realdevice = tmp = strdup(device); + tmp = strchr(tmp, '/'); + if (tmp != NULL) { + *tmp++ = '\0'; + driveidx = atoi(tmp); + } + + if (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + goto out; + } + + ioReturnValue = IOMasterPort(bootstrap_port, &masterPort); + + if (ioReturnValue != kIOReturnSuccess) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Couldn't get a master IOKit port. Error %d", + ioReturnValue); + goto out; + } + + dict = IOServiceMatching(realdevice); + if (dict == NULL) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Couldn't create dictionary for searching"); + goto out; + } + + ioReturnValue = IOServiceGetMatchingServices(masterPort, dict, + &scsiObjectIterator); + dict = NULL; + + if (scsiObjectIterator == NULL || + (ioReturnValue != kIOReturnSuccess)) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "No matching device %s found.", device); + goto out; + } + + if (driveidx <= 0) + driveidx = 1; + + idx = 1; + while ((scsiDevice = IOIteratorNext(scsiObjectIterator)) != NULL) { + if (idx == driveidx) + break; + IOObjectRelease(scsiDevice); + scsiDevice = NULL; + idx++; + } + + if (scsiDevice == NULL) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "No matching device found. Iterator failed."); + goto out; + } + + ioReturnValue = IOCreatePlugInInterfaceForService(scsiDevice, + kIOMMCDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, + &plugInInterface, &score); + if (ioReturnValue != kIOReturnSuccess) { + goto try_generic; + } + + plugInResult = (*plugInInterface)->QueryInterface(plugInInterface, + CFUUIDGetUUIDBytes(kIOMMCDeviceInterfaceID), + (LPVOID)&mmcDeviceInterface); + + if (plugInResult != KERN_SUCCESS) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Unable to get MMC Interface: 0x%lX", + (long)plugInResult); + + goto out; + } + + scsiTaskDeviceInterface = + (*mmcDeviceInterface)->GetSCSITaskDeviceInterface(mmcDeviceInterface); + + if (scsiTaskDeviceInterface == NULL) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Failed to get taskDeviceInterface"); + goto out; + } + + goto init; + +try_generic: + ioReturnValue = IOCreatePlugInInterfaceForService(scsiDevice, + kIOSCSITaskDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, + &plugInInterface, &score); + if (ioReturnValue != kIOReturnSuccess) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Unable to get plugin Interface: %x", + ioReturnValue); + goto out; + } + + plugInResult = (*plugInInterface)->QueryInterface(plugInInterface, + CFUUIDGetUUIDBytes(kIOSCSITaskDeviceInterfaceID), + (LPVOID)&scsiTaskDeviceInterface); + + if (plugInResult != KERN_SUCCESS) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Unable to get generic Interface: 0x%lX", + (long)plugInResult); + + goto out; + } + +init: + ioReturnValue = + (*scsiTaskDeviceInterface)->ObtainExclusiveAccess(scsiTaskDeviceInterface); + + if (ioReturnValue != kIOReturnSuccess) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Unable to get exclusive access to device"); + goto out; + } + + if (mmcDeviceInterface) { + (*mmcDeviceInterface)->AddRef(mmcDeviceInterface); + } + (*scsiTaskDeviceInterface)->AddRef(scsiTaskDeviceInterface); + usallocal(usalp)->mmcDeviceInterface = mmcDeviceInterface; + usallocal(usalp)->scsiTaskDeviceInterface = scsiTaskDeviceInterface; + usallocal(usalp)->masterPort = masterPort; + usal_settarget(usalp, 0, 0, 0); + err = 1; + +out: + if (scsiTaskDeviceInterface != NULL) { + (*scsiTaskDeviceInterface)->Release(scsiTaskDeviceInterface); + } + + if (plugInInterface != NULL) { + (*plugInInterface)->Release(plugInInterface); + } + + if (scsiDevice != NULL) { + IOObjectRelease(scsiDevice); + } + + if (scsiObjectIterator != NULL) { + IOObjectRelease(scsiObjectIterator); + } + + if (err < 0) { + if (usalp->local) { + free(usalp->local); + usalp->local = NULL; + } + + if (masterPort) { + mach_port_deallocate(mach_task_self(), masterPort); + } + } + + if (dict != NULL) { + CFRelease(dict); + } + + if (realdevice != NULL) { + free(realdevice); + } + return (err); +} + +static int +usalo_close(SCSI *usalp) +{ + SCSITaskDeviceInterface **sc; + MMCDeviceInterface **mmc; + + if (usalp->local == NULL) + return (-1); + + sc = usallocal(usalp)->scsiTaskDeviceInterface; + (*sc)->ReleaseExclusiveAccess(sc); + (*sc)->Release(sc); + usallocal(usalp)->scsiTaskDeviceInterface = NULL; + + mmc = usallocal(usalp)->mmcDeviceInterface; + if (mmc != NULL) + (*mmc)->Release(mmc); + + mach_port_deallocate(mach_task_self(), usallocal(usalp)->masterPort); + + free(usalp->local); + usalp->local = NULL; + + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + long maxdma = MAX_DMA_NEXT; +#ifdef SGIOCMAXDMA + int m; + + if (ioctl(usallocal(usalp)->usalfile, SGIOCMAXDMA, &m) >= 0) { + maxdma = m; + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "maxdma: %d\n", maxdma); + } + } +#endif + return (maxdma); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = malloc((size_t)(amt)); + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + usalp->bufbase = NULL; +} + +static BOOL +usalo_havebus(SCSI *usalp, int busno) +{ + if (busno == 0) + return (TRUE); + return (FALSE); +} + +static int +usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun) +{ + 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) +{ + if (what == SCG_RESET_NOP) + return (0); + if (what != SCG_RESET_BUS) { + errno = EINVAL; + return (-1); + } + + errno = 0; + return (-1); +} + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + SCSITaskDeviceInterface **sc = NULL; + SCSITaskInterface **cmd = NULL; + IOVirtualRange iov; + SCSI_Sense_Data senseData; + SCSITaskStatus status; + UInt64 bytesTransferred; + IOReturn ioReturnValue; + int ret = 0; + + if (usalp->local == NULL) { + return (-1); + } + + sc = usallocal(usalp)->scsiTaskDeviceInterface; + + cmd = (*sc)->CreateSCSITask(sc); + if (cmd == NULL) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Failed to create SCSI task"); + ret = -1; + + sp->error = SCG_FATAL; + sp->ux_errno = EIO; + goto out; + } + + + iov.address = (IOVirtualAddress) sp->addr; + iov.length = sp->size; + + ioReturnValue = (*cmd)->SetCommandDescriptorBlock(cmd, + sp->cdb.cmd_cdb, sp->cdb_len); + + if (ioReturnValue != kIOReturnSuccess) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "SetCommandDescriptorBlock failed with status %x", + ioReturnValue); + ret = -1; + goto out; + } + + ioReturnValue = (*cmd)->SetScatterGatherEntries(cmd, &iov, 1, sp->size, + (sp->flags & SCG_RECV_DATA) ? + kSCSIDataTransfer_FromTargetToInitiator : + kSCSIDataTransfer_FromInitiatorToTarget); + if (ioReturnValue != kIOReturnSuccess) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "SetScatterGatherEntries failed with status %x", + ioReturnValue); + ret = -1; + goto out; + } + + ioReturnValue = (*cmd)->SetTimeoutDuration(cmd, sp->timeout * 1000); + if (ioReturnValue != kIOReturnSuccess) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "SetTimeoutDuration failed with status %x", + ioReturnValue); + ret = -1; + goto out; + } + + memset(&senseData, 0, sizeof (senseData)); + + seterrno(0); + ioReturnValue = (*cmd)->ExecuteTaskSync(cmd, + &senseData, &status, &bytesTransferred); + + sp->resid = sp->size - bytesTransferred; + sp->error = SCG_NO_ERROR; + sp->ux_errno = geterrno(); + + if (ioReturnValue != kIOReturnSuccess) { + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Command execution failed with status %x", + ioReturnValue); + sp->error = SCG_RETRYABLE; + ret = -1; + goto out; + } + + memset(&sp->scb, 0, sizeof (sp->scb)); + memset(&sp->u_sense.cmd_sense, 0, sizeof (sp->u_sense.cmd_sense)); + if (senseData.VALID_RESPONSE_CODE != 0 || status == 0x02) { + /* + * There is no sense length - we need to asume that + * we always get 18 bytes. + */ + sp->sense_count = kSenseDefaultSize; + memmove(&sp->u_sense.cmd_sense, &senseData, kSenseDefaultSize); + if (sp->ux_errno == 0) + sp->ux_errno = EIO; + } + + sp->u_scb.cmd_scb[0] = status; + + /* ??? */ + if (status == kSCSITaskStatus_No_Status) { + sp->error = SCG_RETRYABLE; + ret = -1; + goto out; + } + /* + * XXX Is it possible to have other senseful SCSI transport error codes? + */ + +out: + if (cmd != NULL) { + (*cmd)->Release(cmd); + } + + return (ret); +} diff --git a/libusal/scsi-next.c b/libusal/scsi-next.c new file mode 100644 index 0000000..bfbe2b3 --- /dev/null +++ b/libusal/scsi-next.c @@ -0,0 +1,419 @@ +/* + * 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-next.c 1.32 04/01/15 Copyright 1997 J. Schilling */ +/* + * Interface for the NeXT Step generic SCSI implementation. + * + * This is a hack, that tries to emulate the functionality + * of the usal driver. + * + * 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. + * + * Copyright (c) 1997 J. Schilling + */ +/* + * 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. + */ + +#include <bsd/dev/scsireg.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-next.c-1.32"; /* The version for this transport*/ + +#define MAX_SCG 16 /* Max # of SCSI controllers */ +#define MAX_TGT 16 +#define MAX_LUN 8 + +struct usal_local { + short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN]; + int usalfile; + int max_scsibus; + int cur_scsibus; + int cur_target; + int cur_lun; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +/*#define MAX_DMA_NEXT (32*1024)*/ +#define MAX_DMA_NEXT (64*1024) /* Check if this is not too big */ + + +static BOOL usal_setup(SCSI *usalp, int busno, int tgt, int tlun, BOOL ex); + +/* + * 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, "SGIOCREQ", "Generic 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); + register int f; + register int i; + char devname[64]; + + 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); + + usallocal(usalp)->usalfile = -1; + usallocal(usalp)->max_scsibus = -1; + usallocal(usalp)->cur_scsibus = -1; + usallocal(usalp)->cur_target = -1; + usallocal(usalp)->cur_lun = -1; + } + + for (i = 0; i < 4; i++) { + snprintf(devname, sizeof (devname), "/dev/sg%d", i); + f = open(devname, O_RDWR); + if (usalp->debug > 0) + errmsg("open(devname: '%s') : %d\n", devname, f); + if (f < 0) + continue; + usallocal(usalp)->usalfile = f; + break; + + } + if (f >= 0) { + if (usallocal(usalp)->max_scsibus < 0) { + for (i = 0; i < MAX_SCG; i++) { + if (!SCGO_HAVEBUS(usalp, i)) + break; + } + usallocal(usalp)->max_scsibus = i; + } + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "maxbus: %d\n", usallocal(usalp)->max_scsibus); + } + if (usallocal(usalp)->max_scsibus <= 0) { + usallocal(usalp)->max_scsibus = 1; + usallocal(usalp)->cur_scsibus = 0; + } + + ioctl(f, SGIOCENAS); + if (busno > 0 && tgt > 0 && tlun > 0) + usal_setup(usalp, busno, tgt, tlun, TRUE); + return (1); + } + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '/dev/sg*'"); + return (0); +} + +static int +usalo_close(SCSI *usalp) +{ + if (usalp->local == NULL) + return (-1); + + if (usallocal(usalp)->usalfile >= 0) + close(usallocal(usalp)->usalfile); + usallocal(usalp)->usalfile = -1; + return (0); +} + +static BOOL +usal_setup(SCSI *usalp, int busno, int tgt, int tlun, BOOL ex) +{ + scsi_adr_t sadr; + + sadr.sa_target = tgt; + sadr.sa_lun = tlun; + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usal_setup curbus %d -> %d\n", usallocal(usalp)->cur_scsibus, busno); + } + + if (usalp->debug > 0 && ((usallocal(usalp)->cur_scsibus < 0 || usallocal(usalp)->cur_scsibus != busno))) + fprintf((FILE *)usalp->errfile, "setting SCSI bus to: %d\n", busno); + if ((usallocal(usalp)->cur_scsibus < 0 || usallocal(usalp)->cur_scsibus != busno) && + ioctl(usallocal(usalp)->usalfile, SGIOCCNTR, &busno) < 0) { + + usallocal(usalp)->cur_scsibus = -1; /* Driver is in undefined state */ + if (ex) +/* comerr("Cannot set SCSI bus\n");*/ + errmsg("Cannot set SCSI bus\n"); + return (FALSE); + } + usallocal(usalp)->cur_scsibus = busno; + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "setting target/lun to: %d/%d\n", tgt, tlun); + } + if (ioctl(usallocal(usalp)->usalfile, SGIOCSTL, &sadr) < 0) { + if (ex) + comerr("Cannot set SCSI address\n"); + return (FALSE); + } + usallocal(usalp)->cur_scsibus = busno; + usallocal(usalp)->cur_target = tgt; + usallocal(usalp)->cur_lun = tlun; + return (TRUE); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + long maxdma = MAX_DMA_NEXT; +#ifdef SGIOCMAXDMA + int m; + + if (ioctl(usallocal(usalp)->usalfile, SGIOCMAXDMA, &m) >= 0) { + maxdma = m; + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "maxdma: %d\n", maxdma); + } + } +#endif + return (maxdma); +} +#ifdef XXX +#define SGIOCENAS _IO('s', 2) /* enable autosense */ +#define SGIOCDAS _IO('s', 3) /* disable autosense */ +#define SGIOCRST _IO('s', 4) /* reset SCSI bus */ +#define SGIOCCNTR _IOW('s', 6, int) /* select controller */ +#define SGIOCGAS _IOR('s', 7, int) /* get autosense */ +#define SGIOCMAXDMA _IOR('s', 8, int) /* max DMA size */ +#define SGIOCNUMTARGS _IOR('s', 9, int) /* # of targets/bus */ +#endif + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = valloc((size_t)(amt)); + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + usalp->bufbase = NULL; +} + +static BOOL +usalo_havebus(SCSI *usalp, int busno) +{ + if (busno < 0 || busno >= MAX_SCG) + return (FALSE); + + if (usalp->local == NULL) + return (FALSE); + + if (usallocal(usalp)->max_scsibus > 0 && busno >= usallocal(usalp)->max_scsibus) + return (FALSE); + + return (usal_setup(usalp, busno, 0, 0, FALSE)); +} + +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); + if (usallocal(usalp)->max_scsibus > 0 && busno >= usallocal(usalp)->max_scsibus) + return (-1); + + if (usalp->local == NULL) + return (-1); + + if ((busno != usallocal(usalp)->cur_scsibus) || (tgt != usallocal(usalp)->cur_target) || (tlun != usallocal(usalp)->cur_lun)) { + if (!usal_setup(usalp, busno, tgt, tlun, FALSE)) + return (-1); + } + return (usallocal(usalp)->usalfile); +} + +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) +{ + if (what == SCG_RESET_NOP) + return (0); + if (what != SCG_RESET_BUS) { + errno = EINVAL; + return (-1); + } + return (ioctl(usalp->fd, SGIOCRST, 0)); +} + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + struct scsi_req req; + register long *lp1; + register long *lp2; + int ret = 0; + + if (usalp->fd < 0 || (sp->cdb_len > sizeof (req.sr_cdb))) { + sp->error = SCG_FATAL; + sp->ux_errno = EIO; + return (0); + } + fillbytes(&req, sizeof (req), '\0'); + movebytes(sp->cdb.cmd_cdb, &req.sr_cdb, sp->cdb_len); + if (sp->size) { + req.sr_dma_dir = SR_DMA_WR; + if (sp->flags & SCG_RECV_DATA) + req.sr_dma_dir = SR_DMA_RD; + } + req.sr_addr = sp->addr; + req.sr_dma_max = sp->size; + req.sr_ioto = sp->timeout; + if (ioctl(usalp->fd, SGIOCREQ, (void *)&req) < 0) { + ret = -1; + sp->ux_errno = geterrno(); + if (sp->ux_errno != ENOTTY) + ret = 0; + } else { + sp->ux_errno = 0; + } + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, "dma_dir: %X\n", req.sr_dma_dir); + fprintf((FILE *)usalp->errfile, "dma_addr: %X\n", req.sr_addr); + fprintf((FILE *)usalp->errfile, "io_time: %d\n", req.sr_ioto); + fprintf((FILE *)usalp->errfile, "io_status: %d\n", req.sr_io_status); + fprintf((FILE *)usalp->errfile, "scsi_status: %X\n", req.sr_scsi_status); + fprintf((FILE *)usalp->errfile, "dma_xfer: %d\n", req.sr_dma_xfr); + } + sp->u_scb.cmd_scb[0] = req.sr_scsi_status; + sp->sense_count = sizeof (esense_reply_t); + if (sp->sense_count > sp->sense_len) + sp->sense_count = sp->sense_len; + if (sp->sense_count > SCG_MAX_SENSE) + sp->sense_count = SCG_MAX_SENSE; + if (sp->sense_count < 0) + sp->sense_count = 0; + movebytes(&req.sr_esense, sp->u_sense.cmd_sense, sp->sense_count); + sp->resid = sp->size - req.sr_dma_xfr; + + switch (req.sr_io_status) { + + case SR_IOST_GOOD: sp->error = SCG_NO_ERROR; break; + + case SR_IOST_CHKSNV: sp->sense_count = 0; + case SR_IOST_CHKSV: sp->error = SCG_RETRYABLE; + break; + + case SR_IOST_SELTO: + case SR_IOST_DMAOR: + sp->error = SCG_FATAL; break; + + case SR_IOST_IOTO: sp->error = SCG_TIMEOUT; break; + + case SR_IOST_PERM: + case SR_IOST_NOPEN: + sp->error = SCG_FATAL; + ret = (-1); + break; + + default: sp->error = SCG_RETRYABLE; break; + + } + return (ret); +} diff --git a/libusal/scsi-openserver.c b/libusal/scsi-openserver.c new file mode 100644 index 0000000..d192302 --- /dev/null +++ b/libusal/scsi-openserver.c @@ -0,0 +1,1015 @@ +/* + * 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-openserver.c 1.31 04/01/15 Copyright 1998 J. Schilling, Santa Cruz Operation */ +/* + * Interface for the SCO SCSI implementation. + * + * 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. + * + * Copyright (c) 1998 J. Schilling, Santa Cruz Operation + */ +/* + * 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 + +#include <sys/scsicmd.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-openserver.c-1.31"; /* The version for this transport*/ + +#define MAX_SCG 16 /* Max # of cdrom devices */ +#define MAX_TGT 16 /* Not really needed */ +#define MAX_LUN 8 /* Not really needed */ + +#define MAX_DMA (64*1024) + +#define MAXPATH 256 /* max length of devicepath */ +#define MAXLINE 80 /* max length of input line */ +#define MAXSCSI 99 /* max number of mscsi lines */ +#define MAXDRVN 10 /* max length of drivername */ + +#define DEV_DIR "/tmp" +#define DEV_NAME "usal.s%1dt%1dl%1d" + +/* + * --------------------------------------------------------------------- + * We will only deal with cdroms by default! Only if you set a specific + * environment variable, we will scan "all" devices ! + * Set LIBSCG_SCAN_ALL to any value to enable access to all your SCSI + * devices. + * + * The upcoming support for USB will be for USB 1.1, so as this is not + * tested yet, we will currently ignore drives connect to the USB stack + * (usbha controller) regardless of having set LIBSCG_SCAN_ALL or not! + */ + +#define DEV_ROOT "/dev/dsk/0s0" + +#define DEV_SDSK "/dev/rdsk/%ds0" +#define DEV_SROM "/dev/rcd%d" +#define DEV_STP "/dev/xStp%d" +#define DEV_SFLP "/dev/rdsk/fp%dh" + +#define SCAN_DEV "%s%s%d%d%d%d" + +#define SCSI_CFG "/etc/sconf -r" /* no. of configured devices */ +#define SCSI_DEV "/etc/sconf -g %d" /* read line 'n' of mscsi tbl */ + +#define DRV_ATAPI "wd" /* SCO OpenServer IDE driver */ +#define DRV_USB "usbha" /* SCO OpenServer USB driver */ +#define DRV_NOHA "noha" /* IDE/ATAPI device configured, */ + /* but missing ! */ + + +#define T_DISK "Sdsk" /* SCO OpenServer SCSI disk */ +#define T_CDROM "Srom" /* SCO OpenServer SCSI cdrom */ +#define T_TAPE "Stp" /* SCO OpenServer SCSI tape */ +#define T_FLOPPY "Sflp" /* SCO OpenServer SCSI floppy */ + + +/* + * --------------------------------------------------------------------- + * Environment variables to control certain functionality + */ + +#define SCAN_ALL "LIBSCG_SCAN_ALL" /* enable access for all devices */ +#define SCSI_USER_CMD "LIBSCG_SCSIUSERCMD" /* use old SCSIUSERCMD ioctl() */ +#define DMA_OVERRIDE "LIBSCG_MAX_DMA" /* override MAX_DMA value */ +#define ENABLE_USB "LIBSCG_ENABLE_USB" /* enable access of USB devices */ + +static int scan_all = 0; /* don't scan all devices by default */ +static int scsiusercmd = 0; /* use SCSIUSERCMD2 ioctl by default */ +static int enable_usb = 0; /* don't scan USB devices by default */ +static long max_dma = MAX_DMA; /* use MAX_DMA DMA buffer by default */ + + +/* + * --------------------------------------------------------------------- + * There are two scsi passthrough ioctl() on SCO OpenServer 5.0.[45], + * while there is only one available on SCO OpenServer 5.0.[02]. + * + * The SCSIUSERCMD ioctl is available on all OpenServer 5 + * + * The SCSIUSERCMD2 ioctl which executes the usercmd and reads the sense + * in one go, is only available from 5.0.4 onwards. + * + * By default we will use the SCSIUSERCMD2 ioctl(), in order to execute + * the SCSIUSERCMD ioctl() instead set the environment variable + * LIBSCG_SCSIUSERCMD to any value. Using the olderSCSIUSERCMD ioctl() will + * if the SCSI commands returns a CHECK CONDITION status, run a seperate + * REQUEST_SENSE command immediately. But we need to remember that in a + * multi-tasking environment, there might be other code which has accessed + * the device in between these two steps and therefore the sense code + * is no longer valid !!! + * + * NOTE: There are problems with the usage of AHA 154X controllers + * and SCSIUSERCMD2 such as nonsense (weird) output on cdrecord -scanbus + * + */ + + +typedef struct usal2sdi { + + int valid; + int open; + int atapi; + int fd; + int lmscsi; + +} usal2sdi_t; + +static usal2sdi_t sdidevs [MAX_SCG][MAX_TGT][MAX_LUN]; + +typedef struct amscsi { + char typ[MAXDRVN]; + char drv[MAXDRVN]; + int hba; + int bus; + int usal; + int tgt; + int lun; + char dev[MAXPATH]; + +} amscsi_t; + +struct usal_local { + short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN]; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +static int sort_mscsi(const void *l1, const void *l2); +static int openserver_init(SCSI *usalp); +static void cp_usal2sco(struct scsicmd2 *sco, struct usal_cmd *usal); +static void cp_sco2usal(struct scsicmd2 *sco, struct usal_cmd *usal); + +/* + * ------------------------------------------------------------------------- + * SCO OpenServer does not have a generic scsi device driver, which can + * be used to access any configured scsi device. But we can use the "Sxxx" + * scsi peripherial drivers passthrough ioctl() (SCSIUSERCMD / SCSIUSERCMD2) + * to send scsi user comands to any target device controlled by the + * corresponding target driver. + * + * This passthrough implementation for libusal currently allows to + * handle the following devices classes: + * + * 1. DISK handled by Sdsk + * 2. CD-ROM handled by Srom + * 3. TAPES handled by Stp + * 4. FLOPPY handled by Sflp + * + * NOTE: The libusal OpenServer passthrough routines have changed with + * cdrecord-1.8 to enable the -scanbus option. Therefore the + * addressing scheme is now the same as used on many other platforms + * like Solaris, Linux etc. + * + * =============================================================== + * RUN 'cdrecord -scanbus' TO SEE THE DEVICE ADDRESSES YOU CAN USE + * =============================================================== + * + */ + +/* + * 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, "SCSIUSERCMD/SCSIUSERCMD2", "Generic SCSI", + "", "bus,target,lun", "1,2,0", TRUE, FALSE); + return (0); +} + +/* + * --------------------------------------------------------------- + * This routine sorts the amscsi_t lines on the following columns + * in ascending order: + * + * 1. drv - driver name + * 2. bus - scsibus per controller + * 3. tgt - target id of device + * 4. lun - lun of the device + * + */ + + +static int +sort_mscsi(const void *l1, const void *l2) +{ + amscsi_t *t1 = (amscsi_t *) l1; + amscsi_t *t2 = (amscsi_t *) l2; + + if (strcmp(t1->drv, t2->drv) == 0) { + if (t1->bus < t2->bus) { + return (-1); + + } else if (t1->bus > t2->bus) { + return (1); + + } else if (t1->tgt < t2->tgt) { + return (-1); + + } else if (t1->tgt > t2->tgt) { + return (1); + + } else if (t1->lun < t2->lun) { + return (-1); + + } else if (t1->lun > t2->lun) { + return (1); + } else { + return (0); + } + } else { + return (strcmp(t1->drv, t2->drv)); + } +} + +/* + * --------------------------------------------------------------- + * This routine is introduced to find all scsi devices which are + * currently configured into the kernel. This is done by reading + * the dynamic kernel mscsi tables and parse the resulting lines. + * As the output of 'sconf' is not directly usable the information + * found is to be sorted and re-arranged to be used with the libusal + * routines. + * + * NOTE: One problem is currently still not solved ! If you don't + * have a media in your CD-ROM/CD-Writer we are not able to + * do an open() and therefore will set the drive to be not + * available (valid=0). + * + * This will for example cause cdrecord to not list the drive + * in the -scanbus output. + * + */ + +static int +openserver_init(SCSI *usalp) +{ + FILE *cmd; + int nusal = -1, lhba = -1, lbus = -1; + int nSrom = -1, nSdsk = -1, nStp = -1, nSflp = -1; + int atapi, fd, nopen = 0; + int pos = 0, len = 0, nlm = 0; + int s = 0, t = 0, l = 0; + int ide_rootdisk = 0; + long dma_override = 0; + int mscsi; + char sconf[MAXLINE]; + char lines[MAXLINE]; + char drvid[MAXDRVN]; + amscsi_t cmtbl[MAXSCSI]; + char dname[MAXPATH]; + char **evsave; +extern char **environ; + + + for (s = 0; s < MAX_SCG; s++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + sdidevs[s][t][l].valid = 0; + sdidevs[s][t][l].open = -1; + sdidevs[s][t][l].atapi = -1; + sdidevs[s][t][l].fd = -1; + sdidevs[s][t][l].lmscsi = -1; + } + } + } + + /* Check whether we want to use the older SCSIUSERCMD ioctl() */ + + if (getenv(SCSI_USER_CMD) != NULL) { + scsiusercmd = 1; + } + + /* + * Check whether we want to scan all devices + */ + if (getenv(SCAN_ALL) != NULL) { + scan_all = 1; + } + + /* + * Check whether we want to use USB devices + */ + if (getenv(ENABLE_USB) != NULL) { + enable_usb = 1; + } + + /* + * Check whether we want to override the MAX_DMA value + */ + if (getenv(DMA_OVERRIDE) != NULL) { + dma_override = atol(getenv(DMA_OVERRIDE)); + if ((dma_override >= 1) && (dma_override <= (256))) + max_dma = dma_override * 1024; + } + + + /* read sconf -r and get number of kernel mscsi lines ! */ + + evsave = environ; + environ = 0; + if ((cmd = popen(SCSI_CFG, "r")) == NULL) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Error popen() for \"%s\"", + SCSI_CFG); + environ = evsave; + return (-1); + } + environ = evsave; + + if (fgets(lines, MAXLINE, cmd) == NULL) { + errno = EIO; + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Error reading popen() for \"%s\"", + SCSI_CFG); + return (-1); + } else + nlm = atoi(lines); + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, "-------------------- \n"); + fprintf((FILE *)usalp->errfile, "mscsi lines = %d\n", nlm); + fprintf((FILE *)usalp->errfile, "-------------------- \n"); + } + + if (pclose(cmd) == -1) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Error pclose() for \"%s\"", + SCSI_CFG); + return (-1); + } + + for (l = 0; l < nlm; l++) { + + /* initialize cmtbl entry */ + + cmtbl[l].hba = -1; + cmtbl[l].bus = -1; + cmtbl[l].tgt = -1; + cmtbl[l].lun = -1; + cmtbl[l].usal = -1; + + memset(cmtbl[l].typ, '\0', MAXDRVN); + memset(cmtbl[l].drv, '\0', MAXDRVN); + memset(cmtbl[l].dev, '\0', MAXDRVN); + + /* read sconf -g 'n' and get line of kernel mscsi table! */ + /* the order the lines will be received in will determine */ + /* the device name we can use to open the device */ + + snprintf(sconf, sizeof (sconf), + SCSI_DEV, l + 1); /* enumeration starts with 1 */ + + evsave = environ; + environ = 0; + if ((cmd = popen(sconf, "r")) == NULL) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Error popen() for \"%s\"", + sconf); + environ = evsave; + return (-1); + } + environ = evsave; + + if (fgets(lines, MAXLINE, cmd) == NULL) + break; + + if (pclose(cmd) == -1) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Error pclose() for \"%s\"", + sconf); + return (-1); + } + + sscanf(lines, SCAN_DEV, cmtbl[l].typ, + cmtbl[l].drv, + &cmtbl[l].hba, + &cmtbl[l].bus, + &cmtbl[l].tgt, + &cmtbl[l].lun); + + if (strstr(cmtbl[l].typ, T_DISK) != NULL) { + snprintf(cmtbl[l].dev, sizeof (cmtbl[l].dev), + DEV_SDSK, ++nSdsk); + } + + if (strstr(cmtbl[l].typ, T_CDROM) != NULL) { + snprintf(cmtbl[l].dev, sizeof (cmtbl[l].dev), + DEV_SROM, ++nSrom); + } + + if (strstr(cmtbl[l].typ, T_TAPE) != NULL) { + snprintf(cmtbl[l].dev, sizeof (cmtbl[l].dev), + DEV_STP, ++nStp); + } + + if (strstr(cmtbl[l].typ, T_FLOPPY) != NULL) { + snprintf(cmtbl[l].dev, sizeof (cmtbl[l].dev), + DEV_SFLP, ++nSflp); + } + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "%-4s = %5s(%d,%d,%d,%d) -> %s\n", + cmtbl[l].typ, + cmtbl[l].drv, + cmtbl[l].hba, + cmtbl[l].bus, + cmtbl[l].tgt, + cmtbl[l].lun, + cmtbl[l].dev); + } + + } + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, "-------------------- \n"); + fprintf((FILE *)usalp->errfile, "%2d DISK \n", nSdsk + 1); + fprintf((FILE *)usalp->errfile, "%2d CD-ROM\n", nSrom + 1); + fprintf((FILE *)usalp->errfile, "%2d TAPE \n", nStp + 1); + fprintf((FILE *)usalp->errfile, "%2d FLOPPY\n", nSflp + 1); + fprintf((FILE *)usalp->errfile, "-------------------- \n"); + } + + /* ok, now let's sort this array of scsi devices */ + + qsort((void *) cmtbl, nlm, sizeof (amscsi_t), sort_mscsi); + + if (usalp->debug > 0) { + for (l = 0; l < nlm; l++) + fprintf((FILE *)usalp->errfile, + "%-4s = %5s(%d,%d,%d,%d) -> %s\n", + cmtbl[l].typ, + cmtbl[l].drv, + cmtbl[l].hba, + cmtbl[l].bus, + cmtbl[l].tgt, + cmtbl[l].lun, + cmtbl[l].dev); + fprintf((FILE *)usalp->errfile, "-------------------- \n"); + } + + /* find root disk controller to make it usal 0 */ + + /* + * if we have disk(s) found in the mscsi table, we still + * don't know if the rootdisk is among these, there can + * be a IDE rootdisk as well, but it's not listed in + * the mscsi table. + */ + + t = 0; + if (nSdsk > 0) { + for (l = 0; l < nlm; l++) + if (strcmp(cmtbl[l].dev, DEV_ROOT) == 0) + t = l; + } else { + + /* + * we haven't found a disk in mscsi, so we definitely + * have an IDE disk on a wd adapter as IDE disks are + * not listed as SCSI disks in the kernel mscsi table + */ + ide_rootdisk = 1; + + } + + if (!(ide_rootdisk) && (usalp->debug > 0)) { + fprintf((FILE *)usalp->errfile, + "root = %5s(%d,%d,%d,%d) -> %s\n", + cmtbl[t].drv, + cmtbl[t].hba, + cmtbl[t].bus, + cmtbl[t].tgt, + cmtbl[t].lun, + cmtbl[t].dev); + fprintf((FILE *)usalp->errfile, "-------------------- \n"); + } + + /* calculate usal from drv, hba and bus */ + + strcpy(drvid, ""); + + for (l = 0, s = t; l < nlm; l++, s = (t + l) % nlm) { + + if (strcmp(drvid, cmtbl[s].drv) != 0) { + strcpy(drvid, cmtbl[s].drv); + lhba = cmtbl[s].hba; + lbus = cmtbl[s].bus; + cmtbl[s].usal = ++nusal; + + } else if (cmtbl[s].hba != lhba) { + lhba = cmtbl[s].hba; + lbus = cmtbl[s].bus; + cmtbl[s].usal = ++nusal; + + } else if (cmtbl[s].bus != lbus) { + lbus = cmtbl[s].bus; + cmtbl[s].usal = ++nusal; + } else { + cmtbl[s].usal = nusal; + } + sdidevs[cmtbl[s].usal][cmtbl[s].tgt][cmtbl[s].lun].open = 0; + + /* check whether we want to open all devices or it's a CDROM */ + + if ((scan_all) || (strcmp(cmtbl[s].typ, T_CDROM) == 0)) + sdidevs[cmtbl[s].usal][cmtbl[s].tgt][cmtbl[s].lun].valid = 1; + + /* check whether we have an IDE/ATAPI device */ + + if (strcmp(cmtbl[s].drv, DRV_ATAPI) == 0) + sdidevs[cmtbl[s].usal][cmtbl[s].tgt][cmtbl[s].lun].atapi = 1; + + /* don't open a USB device if enable_usb is not set */ + + if (strcmp(cmtbl[s].drv, DRV_USB) == 0) + sdidevs[cmtbl[s].usal][cmtbl[s].tgt][cmtbl[s].lun].valid = enable_usb; + + /* don't open a IDE/ATAPI device which is missing but configured */ + + if (strcmp(cmtbl[s].drv, DRV_NOHA) == 0) + sdidevs[cmtbl[s].usal][cmtbl[s].tgt][cmtbl[s].lun].valid = 0; + + + sdidevs[cmtbl[s].usal][cmtbl[s].tgt][cmtbl[s].lun].lmscsi = s; + + } + + + /* open all yet valid device nodes */ + + for (s = 0; s < MAX_SCG; s++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + + if (sdidevs[s][t][l].valid == 0) + continue; + + /* Open pass-through device node */ + + mscsi = sdidevs[s][t][l].lmscsi; + + strcpy(dname, cmtbl[mscsi].dev); + + /* + * ------------------------------------------------------------------ + * NOTE: If we can't open the device, we will set the device invalid! + * ------------------------------------------------------------------ + */ + errno = 0; + if ((fd = open(dname, (O_RDONLY | O_NONBLOCK))) < 0) { + sdidevs[s][t][l].valid = 0; + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "%5s(%d,%d,%d,%d) -> %s open() failed: errno = %d (%s)\n", + cmtbl[mscsi].drv, + cmtbl[mscsi].hba, + cmtbl[mscsi].bus, + cmtbl[mscsi].tgt, + cmtbl[mscsi].lun, + cmtbl[mscsi].dev, + errno, + strerror(errno)); + } + continue; + } + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "%d,%d,%d => %5s(%d,%d,%d,%d) -> %d : %s \n", + s, t, l, + cmtbl[mscsi].drv, + cmtbl[mscsi].hba, + cmtbl[mscsi].bus, + cmtbl[mscsi].tgt, + cmtbl[mscsi].lun, + cmtbl[mscsi].usal, + cmtbl[mscsi].dev); + } + + sdidevs[s][t][l].fd = fd; + sdidevs[s][t][l].open = 1; + nopen++; + usallocal(usalp)->usalfiles[s][t][l] = (short) fd; + } + } + } + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, "-------------------- \n"); + fprintf((FILE *)usalp->errfile, "nopen = %d devices \n", nopen); + fprintf((FILE *)usalp->errfile, "-------------------- \n"); + } + + return (nopen); +} + + +static int +usalo_open(SCSI *usalp, char *device) +{ + int busno = usal_scsibus(usalp); + int tgt = usal_target(usalp); + int tlun = usal_lun(usalp); + int f, b, t, l; + int nopen = 0; + char devname[64]; + + 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 (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } + + if (*device != '\0') { /* we don't allow old dev usage */ + errno = EINVAL; + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Open by 'devname' no longer supported on this OS"); + return (-1); + } + + return (openserver_init(usalp)); + +} + +static int +usalo_close(SCSI *usalp) +{ + register int f; + register int b; + register int t; + register int l; + + if (usalp->local == NULL) + return (-1); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + + f = usallocal(usalp)->usalfiles[b][t][l]; + if (f >= 0) + close(f); + + sdidevs[b][t][l].fd = -1; + sdidevs[b][t][l].open = 0; + sdidevs[b][t][l].valid = 0; + + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + return (max_dma); +} + + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = valloc((size_t)(amt)); + + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + 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); + + if (usalp->local == NULL) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if (usallocal(usalp)->usalfiles[busno][t][l] >= 0) + return (TRUE); + } + return (FALSE); +} + +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); + + if (usalp->local == NULL) + return (-1); + + return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]); +} + +static int +usalo_initiator_id(SCSI *usalp) +{ + return (-1); + + /* + * We don't know the initiator ID yet, but we can if we parse the + * output of the command 'cat /dev/string/cfg | grep "%adapter"' + * + * Sample line: + * + * %adapter 0xE800-0xE8FF 11 - type=alad ha=0 bus=0 id=7 fts=sto + * + * This tells us that the alad controller 0 has an id of 7 ! + * The parsing should be done in openserver_init(). + * + */ +} + +static int +usalo_isatapi(SCSI *usalp) +{ + return (sdidevs[usal_scsibus(usalp)][usal_target(usalp)][usal_lun(usalp)].atapi); +} + +static int +usalo_reset(SCSI *usalp, int what) +{ + errno = EINVAL; + return (-1); /* no scsi reset available */ +} + +static void +cp_usal2sco(struct scsicmd2 *sco, struct usal_cmd *usal) +{ + sco->cmd.data_ptr = (char *) usal->addr; + sco->cmd.data_len = usal->size; + sco->cmd.cdb_len = usal->cdb_len; + + sco->sense_len = usal->sense_len; + sco->sense_ptr = usal->u_sense.cmd_sense; + + if (!(usal->flags & SCG_RECV_DATA) && (usal->size > 0)) + sco->cmd.is_write = 1; + + if (usal->cdb_len == SC_G0_CDBLEN) + memcpy(sco->cmd.cdb, &usal->cdb.g0_cdb, usal->cdb_len); + + if (usal->cdb_len == SC_G1_CDBLEN) + memcpy(sco->cmd.cdb, &usal->cdb.g1_cdb, usal->cdb_len); + + if (usal->cdb_len == SC_G5_CDBLEN) + memcpy(sco->cmd.cdb, &usal->cdb.g5_cdb, usal->cdb_len); +} + + +static void +cp_sco2usal(struct scsicmd2 *sco, struct usal_cmd *usal) +{ + usal->size = sco->cmd.data_len; + + memset(&usal->scb, 0, sizeof (usal->scb)); + + if (sco->sense_len > SCG_MAX_SENSE) + usal->sense_count = SCG_MAX_SENSE; + else + usal->sense_count = sco->sense_len; + + usal->resid = 0; + + usal->u_scb.cmd_scb[0] = sco->cmd.target_sts; + +} + + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + struct scsicmd2 scsi_cmd; + int i; + Uchar sense_buf[SCG_MAX_SENSE]; + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + + memset(&scsi_cmd, 0, sizeof (scsi_cmd)); + memset(sense_buf, 0, sizeof (sense_buf)); + scsi_cmd.sense_ptr = sense_buf; + scsi_cmd.sense_len = sizeof (sense_buf); + cp_usal2sco(&scsi_cmd, sp); + + errno = 0; + sp->ux_errno = 0; + sp->error = SCG_NO_ERROR; + for (;;) { + int ioctlStatus; + struct scsicmd s_cmd; + + if (scsiusercmd) { /* Use SCSIUSERCMD ioctl() */ + if (usalp->debug > 1) { + fprintf((FILE *)usalp->errfile, "calling SCSIUSERCMD ioctl()\n"); + } + + if ((ioctlStatus = ioctl(usalp->fd, SCSIUSERCMD, &(scsi_cmd.cmd))) < 0) { + if (usalp->debug > 1) { + fprintf((FILE *)usalp->errfile, "returning from SCSIUSERCMD ioctl()\n"); + } + if (errno == EINTR) + continue; + + cp_sco2usal(&scsi_cmd, sp); + sp->ux_errno = errno; + if (errno == 0) + sp->ux_errno = EIO; + sp->error = SCG_RETRYABLE; + + return (0); + } + + if (usalp->debug > 1) { + fprintf((FILE *)usalp->errfile, "returning from SCSIUSERCMD ioctl()\n"); + } + cp_sco2usal(&scsi_cmd, sp); + sp->ux_errno = errno; + + if (scsi_cmd.cmd.target_sts & 0x02) { /* Check Condition & get Sense */ + + if (sp->sense_len > SCG_MAX_SENSE) + sp->sense_len = SCG_MAX_SENSE; + + memset((caddr_t)&s_cmd, 0, sizeof (s_cmd)); + + s_cmd.data_ptr = (caddr_t) sp->u_sense.cmd_sense; + s_cmd.data_len = sp->sense_len; + s_cmd.is_write = 0; + s_cmd.cdb[0] = SC_REQUEST_SENSE; + + while (((ioctlStatus = ioctl(usalp->fd, SCSIUSERCMD, &s_cmd)) < 0) && + (errno == EINTR)) + ; + + sp->sense_count = sp->sense_len; + sp->ux_errno = errno; + + if (errno == 0) + sp->ux_errno = EIO; + sp->error = SCG_NO_ERROR; + } + + if (usalp->debug > 0) { + if (errno != 0) + fprintf((FILE *)usalp->errfile, "ux_errno: %d (%s) \n", sp->ux_errno, strerror(sp->ux_errno)); + if (sp->u_scb.cmd_scb[0] != 0) + fprintf((FILE *)usalp->errfile, "tgt_stat: %d \n", sp->u_scb.cmd_scb[0]); + } + break; + + } else { /* Use SCSIUSERCMD2 ioctl() */ + if (usalp->debug > 1) { + fprintf((FILE *)usalp->errfile, "calling SCSIUSERCMD2 ioctl()\n"); + } + + if ((ioctlStatus = ioctl(usalp->fd, SCSIUSERCMD2, &scsi_cmd)) < 0) { + if (usalp->debug > 1) { + fprintf((FILE *)usalp->errfile, "returning from SCSIUSERCMD2 ioctl()\n"); + } + if (errno == EINTR) + continue; + + cp_sco2usal(&scsi_cmd, sp); + sp->ux_errno = errno; + if (errno == 0) + sp->ux_errno = EIO; + sp->error = SCG_RETRYABLE; + + return (0); + } + if (usalp->debug > 1) { + fprintf((FILE *)usalp->errfile, "returning from SCSIUSERCMD2 ioctl()\n"); + } + + cp_sco2usal(&scsi_cmd, sp); + sp->ux_errno = errno; + + if (scsi_cmd.cmd.target_sts & 0x02) { /* Check Condition */ + if (errno == 0) + sp->ux_errno = EIO; + sp->error = SCG_NO_ERROR; + } + + if (usalp->debug > 0) { + if (errno != 0) + fprintf((FILE *)usalp->errfile, "ux_errno: %d (%s) \n", sp->ux_errno, strerror(sp->ux_errno)); + if (sp->u_scb.cmd_scb[0] != 0) + fprintf((FILE *)usalp->errfile, "tgt_stat: %d \n", sp->u_scb.cmd_scb[0]); + } + break; + + } + } + + return (0); +} + +#define sense u_sense.Sense 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 diff --git a/libusal/scsi-osf.c b/libusal/scsi-osf.c new file mode 100644 index 0000000..79d0708 --- /dev/null +++ b/libusal/scsi-osf.c @@ -0,0 +1,445 @@ +/* + * 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-osf.c 1.26 04/01/15 Copyright 1998 J. Schilling */ +/* + * Interface for Digital UNIX (OSF/1 generic SCSI implementation (/dev/cam). + * + * Created out of the hacks from: + * Stefan Traby <stefan@sime.com> and + * Bruno Achauer <bruno@tk.uni-linz.ac.at> + * + * 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. + * + * Copyright (c) 1998 J. Schilling + */ +/* + * 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. + */ + +#include <sys/types.h> +#include <io/common/iotypes.h> +#include <io/cam/cam.h> +#include <io/cam/uagt.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-osf.c-1.26"; /* The version for this transport*/ + +#define MAX_SCG 16 /* Max # of SCSI controllers */ +#define MAX_TGT 16 +#define MAX_LUN 8 + +struct usal_local { + int usalfile; /* Used for ioctl() */ + short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN]; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +static BOOL scsi_checktgt(SCSI *usalp, int f, int busno, int tgt, int tlun); + +/* + * I don't have any documentation about CAM + */ +#define MAX_DMA_OSF_CAM (64*1024) + +#ifndef AUTO_SENSE_LEN +# define AUTO_SENSE_LEN 32 /* SCG_MAX_SENSE */ +#endif + +/* + * 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, "CAM", "Generic transport independent SCSI (Common Access Method)", + "", "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); + register int b; + register int t; + register int l; + + 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); + usallocal(usalp)->usalfile = -1; + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + usallocal(usalp)->usalfiles[b][t][l] = 0; + } + } + } + + if (usallocal(usalp)->usalfile != -1) /* multiple opens ??? */ + return (1); /* not yet ready .... */ + + if ((usallocal(usalp)->usalfile = open("/dev/cam", O_RDWR, 0)) < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '/dev/cam'"); + return (-1); + } + + if (busno >= 0 && tgt >= 0 && tlun >= 0) { + /* scsi_checktgt() ??? */ + for (l = 0; l < MAX_LUN; l++) + usallocal(usalp)->usalfiles[b][t][l] = 1; + return (1); + } + /* + * There seems to be no clean way to check whether + * a SCSI bus is present in the current system. + * scsi_checktgt() is used as a workaround for this problem. + */ + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + if (scsi_checktgt(usalp, usallocal(usalp)->usalfile, b, t, 0)) { + for (l = 0; l < MAX_LUN; l++) + usallocal(usalp)->usalfiles[b][t][l] = 1; + /* + * Found a target on this bus. + * Comment the 'break' for a complete scan. + */ + break; + } + } + } + return (1); +} + +static int +usalo_close(SCSI *usalp) +{ + if (usalp->local == NULL) + return (-1); + + if (usallocal(usalp)->usalfile >= 0) + close(usallocal(usalp)->usalfile); + usallocal(usalp)->usalfile = -1; + return (0); +} + +/* + * We send a test unit ready command to the target to check whether the + * OS is considering this target to be valid. + * XXX Is this really needed? We should rather let the cmd fail later. + */ +static BOOL +scsi_checktgt(SCSI *usalp, int f, int busno, int tgt, int tlun) +{ + struct usal_cmd *sp = usalp->scmd; + struct usal_cmd sc; + int ret; + int ofd = usalp->fd; + int obus = usal_scsibus(usalp); + int otgt = usal_target(usalp); + int olun = usal_lun(usalp); + + usal_settarget(usalp, busno, tgt, tlun); + usalp->fd = f; + + sc = *sp; + fillbytes((caddr_t)sp, sizeof (*sp), '\0'); + sp->addr = (caddr_t)0; + sp->size = 0; + sp->flags = SCG_DISRE_ENA | SCG_SILENT; + sp->cdb_len = SC_G0_CDBLEN; + sp->sense_len = CCS_SENSE_LEN; + sp->cdb.g0_cdb.cmd = SC_TEST_UNIT_READY; + sp->cdb.g0_cdb.lun = usal_lun(usalp); + + usalo_send(usalp); + usal_settarget(usalp, obus, otgt, olun); + usalp->fd = ofd; + + if (sp->error != SCG_FATAL) + return (TRUE); + ret = sp->ux_errno != EINVAL; + *sp = sc; + return (ret); +} + + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + long maxdma = MAX_DMA_OSF_CAM; + + return (maxdma); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = valloc((size_t)(amt)); + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + usalp->bufbase = NULL; +} + +static BOOL +usalo_havebus(SCSI *usalp, int busno) +{ + register int t; + + if (busno < 0 || busno >= MAX_SCG) + return (FALSE); + + if (usalp->local == NULL) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + if (usallocal(usalp)->usalfiles[busno][t][0] != 0) + return (TRUE); + } + return (FALSE); +} + + +static int +usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun) +{ + if (usalp->local == NULL) + return (-1); + + return ((busno < 0 || busno >= MAX_SCG) ? -1 : usallocal(usalp)->usalfile); +} + +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) +{ + errno = EINVAL; + return (-1); +} + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + CCB_SCSIIO ccb; + UAGT_CAM_CCB ua; + unsigned char *cdb; + CCB_RELSIM relsim; + UAGT_CAM_CCB relua; + int i; + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + + fillbytes(&ua, sizeof (UAGT_CAM_CCB), 0); + fillbytes(&ccb, sizeof (CCB_SCSIIO), 0); + + ua.uagt_ccb = (CCB_HEADER *) &ccb; + ua.uagt_ccblen = sizeof (CCB_SCSIIO); + ccb.cam_ch.my_addr = (CCB_HEADER *) &ccb; + ccb.cam_ch.cam_ccb_len = sizeof (CCB_SCSIIO); + + ua.uagt_snsbuf = ccb.cam_sense_ptr = sp->u_sense.cmd_sense; + ua.uagt_snslen = ccb.cam_sense_len = AUTO_SENSE_LEN; + + cdb = (unsigned char *) ccb.cam_cdb_io.cam_cdb_bytes; + + ccb.cam_timeout = sp->timeout; + + ccb.cam_data_ptr = ua.uagt_buffer = (Uchar *) sp->addr; + ccb.cam_dxfer_len = ua.uagt_buflen = sp->size; + ccb.cam_ch.cam_func_code = XPT_SCSI_IO; + ccb.cam_ch.cam_flags = 0; /* CAM_DIS_CALLBACK; */ + + if (sp->size == 0) { + ccb.cam_data_ptr = ua.uagt_buffer = (Uchar *) NULL; + ccb.cam_ch.cam_flags |= CAM_DIR_NONE; + } else { + if (sp->flags & SCG_RECV_DATA) { + ccb.cam_ch.cam_flags |= CAM_DIR_IN; + } else { + ccb.cam_ch.cam_flags |= CAM_DIR_OUT; + } + } + + ccb.cam_cdb_len = sp->cdb_len; + for (i = 0; i < sp->cdb_len; i++) + cdb[i] = sp->cdb.cmd_cdb[i]; + + ccb.cam_ch.cam_path_id = usal_scsibus(usalp); + ccb.cam_ch.cam_target_id = usal_target(usalp); + ccb.cam_ch.cam_target_lun = usal_lun(usalp); + + sp->sense_count = 0; + sp->ux_errno = 0; + sp->error = SCG_NO_ERROR; + + + if (ioctl(usalp->fd, UAGT_CAM_IO, (caddr_t) &ua) < 0) { + sp->ux_errno = geterrno(); + sp->error = SCG_FATAL; + if (usalp->debug > 0) { + errmsg("ioctl(fd, UAGT_CAM_IO, dev=%d,%d,%d) failed.\n", + usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp)); + } + return (0); + } + if (usalp->debug > 0) { + errmsgno(EX_BAD, "cam_status = 0x%.2X scsi_status = 0x%.2X dev=%d,%d,%d\n", + ccb.cam_ch.cam_status, + ccb.cam_scsi_status, + usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp)); + fflush(stderr); + } + switch (ccb.cam_ch.cam_status & CAM_STATUS_MASK) { + + case CAM_REQ_CMP: break; + + case CAM_SEL_TIMEOUT: sp->error = SCG_FATAL; + sp->ux_errno = EIO; + break; + + case CAM_CMD_TIMEOUT: sp->error = SCG_TIMEOUT; + sp->ux_errno = EIO; + break; + + default: sp->error = SCG_RETRYABLE; + sp->ux_errno = EIO; + break; + } + + sp->u_scb.cmd_scb[0] = ccb.cam_scsi_status; + + if (ccb.cam_ch.cam_status & CAM_AUTOSNS_VALID) { + sp->sense_count = MIN(ccb.cam_sense_len - ccb.cam_sense_resid, + SCG_MAX_SENSE); + sp->sense_count = MIN(sp->sense_count, sp->sense_len); + if (sp->sense_len < 0) + sp->sense_count = 0; + } + sp->resid = ccb.cam_resid; + + + /* + * this is perfectly wrong. + * But without this, we hang... + */ + if (ccb.cam_ch.cam_status & CAM_SIM_QFRZN) { + fillbytes(&relsim, sizeof (CCB_RELSIM), 0); + relsim.cam_ch.cam_ccb_len = sizeof (CCB_SCSIIO); + relsim.cam_ch.cam_func_code = XPT_REL_SIMQ; + relsim.cam_ch.cam_flags = CAM_DIR_IN | CAM_DIS_CALLBACK; + relsim.cam_ch.cam_path_id = usal_scsibus(usalp); + relsim.cam_ch.cam_target_id = usal_target(usalp); + relsim.cam_ch.cam_target_lun = usal_lun(usalp); + + relua.uagt_ccb = (struct ccb_header *) & relsim; /* wrong cast */ + relua.uagt_ccblen = sizeof (relsim); + relua.uagt_buffer = NULL; + relua.uagt_buflen = 0; + + if (ioctl(usalp->fd, UAGT_CAM_IO, (caddr_t) & relua) < 0) + errmsg("DEC CAM -> LMA\n"); + } + return (0); +} diff --git a/libusal/scsi-qnx.c b/libusal/scsi-qnx.c new file mode 100644 index 0000000..7342025 --- /dev/null +++ b/libusal/scsi-qnx.c @@ -0,0 +1,316 @@ +/* + * 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-qnx.c 1.3 04/01/15 Copyright 1998-2003 J. Schilling */ +/* + * Interface for QNX (Neutrino generic SCSI implementation). + * First version adopted from the OSF-1 version by + * Kevin Chiles <kchiles@qnx.com> + * + * 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. + * + * Copyright (c) 1998-2003 J. Schilling + */ +/* + * 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. + */ + +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/dcmd_cam.h> +#include <sys/cam_device.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-qnx.c-1.3"; /* The version for this transport*/ + +#define MAX_SCG 16 /* Max # of SCSI controllers */ +#define MAX_TGT 16 +#define MAX_LUN 8 + +struct usal_local { + int fd; +}; + +#define usallocal(p) ((struct usal_local *)((p)->local)) +#define QNX_CAM_MAX_DMA (32*1024) + +#ifndef AUTO_SENSE_LEN +# define AUTO_SENSE_LEN 32 /* SCG_MAX_SENSE */ +#endif + +/* + * 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 ("Initial Version adopted from OSF-1 by QNX-people"); + return (_usal_auth_cdrkit); + case SCG_SCCS_ID: + return (__sccsid); + } + } + return ((char *)0); +} + +static int +usalo_help(SCSI *usalp, FILE *f) +{ + __usal_help(f, "CAM", "Generic transport independent SCSI (Common Access Method)", + "", "bus,target,lun", "1,2,0", TRUE, FALSE); + return (0); +} + +static int +usalo_open(SCSI *usalp, char *device) +{ + int fd; + + if (device == NULL || *device == '\0') { + errno = EINVAL; + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "'devname' must be specified on this OS"); + return (-1); + } + + if (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + usallocal(usalp)->fd = -1; + } + + if (usallocal(usalp)->fd != -1) /* multiple open? */ + return (1); + + if ((usallocal(usalp)->fd = open(device, O_RDONLY, 0)) < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", device); + return (-1); + } + + usal_settarget(usalp, 0, 0, 0); + + return (1); +} + +static int +usalo_close(SCSI *usalp) +{ + if (usalp->local == NULL) + return (-1); + + if (usallocal(usalp)->fd >= 0) + close(usallocal(usalp)->fd); + usallocal(usalp)->fd = -1; + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + long maxdma = QNX_CAM_MAX_DMA; + + return (maxdma); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + void *addr; + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, "usalo_getbuf: %ld bytes\n", amt); + } + + if ((addr = mmap(NULL, amt, PROT_READ | PROT_WRITE | PROT_NOCACHE, + MAP_ANON | MAP_PHYS | MAP_NOX64K, NOFD, 0)) == MAP_FAILED) { + return (NULL); + } + + usalp->bufbase = addr; + return (addr); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + munmap(usalp->bufbase, QNX_CAM_MAX_DMA); + usalp->bufbase = NULL; +} + +static BOOL +usalo_havebus(SCSI *usalp, int busno) +{ + return (FALSE); +} + + +static int +usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun) +{ + if (usalp->local == NULL) + return (-1); + + return ((busno < 0 || busno >= MAX_SCG) ? -1 : usallocal(usalp)->fd); +} + +static int +usalo_initiator_id(SCSI *usalp) +{ + return (-1); +} + +static int +usalo_isatapi(SCSI *usalp) +{ + cam_devinfo_t cinfo; + + if (devctl(usalp->fd, DCMD_CAM_DEVINFO, &cinfo, sizeof (cinfo), NULL) != EOK) { + return (TRUE); /* default to ATAPI */ + } + return ((cinfo.flags & DEV_ATAPI) ? TRUE : FALSE); +} + +static int +usalo_reset(SCSI *usalp, int what) +{ + errno = EINVAL; + return (-1); +} + +static int +usalo_send(SCSI *usalp) +{ + int i; + struct usal_cmd *sp; + int icnt; + iov_t iov[3]; + CAM_PASS_THRU cpt; + + icnt = 1; + sp = usalp->scmd; + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + + memset(&cpt, 0, sizeof (cpt)); + + sp->sense_count = 0; + sp->ux_errno = 0; + sp->error = SCG_NO_ERROR; + cpt.cam_timeout = sp->timeout; + cpt.cam_cdb_len = sp->cdb_len; + memcpy(cpt.cam_cdb, sp->cdb.cmd_cdb, sp->cdb_len); + + if (sp->sense_len != -1) { + cpt.cam_sense_len = sp->sense_len; + cpt.cam_sense_ptr = sizeof (cpt); /* XXX Offset from start of struct to data ??? */ + icnt++; + } else { + cpt.cam_flags |= CAM_DIS_AUTOSENSE; + } + + if (cpt.cam_dxfer_len = sp->size) { + icnt++; + cpt.cam_data_ptr = (paddr_t)sizeof (cpt) + cpt.cam_sense_len; + if (sp->flags & SCG_RECV_DATA) { + cpt.cam_flags |= CAM_DIR_IN; + } else { + cpt.cam_flags |= CAM_DIR_OUT; + } + } else { + cpt.cam_flags |= CAM_DIR_NONE; + } + + SETIOV(&iov[0], &cpt, sizeof (cpt)); + SETIOV(&iov[1], sp->u_sense.cmd_sense, cpt.cam_sense_len); + SETIOV(&iov[2], sp->addr, sp->size); + if (devctlv(usallocal(usalp)->fd, DCMD_CAM_PASS_THRU, icnt, icnt, iov, iov, NULL)) { + sp->ux_errno = geterrno(); + sp->error = SCG_FATAL; + if (usalp->debug > 0) { + errmsg("cam_io failed\n"); + } + return (0); + } + + sp->resid = cpt.cam_resid; + sp->u_scb.cmd_scb[0] = cpt.cam_scsi_status; + + switch (cpt.cam_status & CAM_STATUS_MASK) { + case CAM_REQ_CMP: + break; + + case CAM_SEL_TIMEOUT: + sp->error = SCG_FATAL; + sp->ux_errno = EIO; + break; + + case CAM_CMD_TIMEOUT: + sp->error = SCG_TIMEOUT; + sp->ux_errno = EIO; + break; + + default: + sp->error = SCG_RETRYABLE; + sp->ux_errno = EIO; + break; + } + + if (cpt.cam_status & CAM_AUTOSNS_VALID) { + sp->sense_count = min(cpt.cam_sense_len - cpt.cam_sense_resid, + SCG_MAX_SENSE); + sp->sense_count = min(sp->sense_count, sp->sense_len); + if (sp->sense_len < 0) + sp->sense_count = 0; + } + + return (0); +} diff --git a/libusal/scsi-remote.c b/libusal/scsi-remote.c new file mode 100644 index 0000000..f9b40d6 --- /dev/null +++ b/libusal/scsi-remote.c @@ -0,0 +1,1213 @@ +/* + * 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. + * + */ + +#define USE_REMOTE +/* @(#)scsi-remote.c 1.18 06/01/12 Copyright 1990,2000-2003 J. Schilling */ +/* + * Remote SCSI user level command transport routines + * + * 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. + * + * Copyright (c) 1990,2000-2003 J. Schilling + */ +/* + * 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. + */ + +#include <mconfig.h> + +#if !defined(HAVE_FORK) || !defined(HAVE_SOCKETPAIR) || !defined(HAVE_DUP2) +#undef USE_RCMD_RSH +#endif +/* + * We may work without getservbyname() if we restructure the code not to + * use the port number if we only use _rcmdrsh(). + */ +#if !defined(HAVE_GETSERVBYNAME) +#undef USE_REMOTE /* Cannot get rcmd() port # */ +#endif +#if (!defined(HAVE_NETDB_H) || !defined(HAVE_RCMD)) && !defined(USE_RCMD_RSH) +#undef USE_REMOTE /* There is no rcmd() */ +#endif + +#ifdef USE_REMOTE +#include <stdio.h> +#include <sys/types.h> +#include <fctldefs.h> +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#include <errno.h> +#include <signal.h> +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif +#include <standard.h> +#include <stdxlib.h> +#include <unixstd.h> +#include <strdefs.h> +#include <schily.h> + +#include <usal/usalcmd.h> +#include <usal/scsitransp.h> + +#if defined(SIGDEFER) || defined(SVR4) +#define signal sigset +#endif + +/* + * On Cygwin, there are no privilleged ports. + * On UNIX, rcmd() uses privilleged port that only work for root. + */ +#ifdef IS_CYGWIN +#define privport_ok() (1) +#else +#ifdef HAVE_GETPPRIV +#define privport_ok() ppriv_ok() +#else +#define privport_ok() (geteuid() == 0) +#endif +#endif + +#define CMD_SIZE 80 + +#define MAX_SCG 16 /* Max # of SCSI controllers */ +#define MAX_TGT 16 +#define MAX_LUN 8 + +/*extern BOOL debug;*/ +LOCAL BOOL debug = 1; + +LOCAL char _usal_trans_version[] = "remote-1.18"; /* The version for remote SCSI */ +LOCAL char _usal_auth_cdrkit[] = "cdrkit-team"; /* The author for this module */ + +LOCAL int usalo_rsend __PR((SCSI *usalp)); +LOCAL char * usalo_rversion __PR((SCSI *usalp, int what)); +LOCAL int usalo_rhelp __PR((SCSI *usalp, FILE *f)); +LOCAL int usalo_ropen __PR((SCSI *usalp, char *device)); +LOCAL int usalo_rclose __PR((SCSI *usalp)); +LOCAL long usalo_rmaxdma __PR((SCSI *usalp, long amt)); +LOCAL void * usalo_rgetbuf __PR((SCSI *usalp, long amt)); +LOCAL void usalo_rfreebuf __PR((SCSI *usalp)); +LOCAL BOOL usalo_rhavebus __PR((SCSI *usalp, int busno)); +LOCAL int usalo_rfileno __PR((SCSI *usalp, int busno, int tgt, int tlun)); +LOCAL int usalo_rinitiator_id __PR((SCSI *usalp)); +LOCAL int usalo_risatapi __PR((SCSI *usalp)); +LOCAL int usalo_rreset __PR((SCSI *usalp, int what)); + +/* + * XXX We should rethink the fd parameter now that we introduced + * XXX the rscsirchar() function and most access of remfd is done + * XXX via usallocal(usalp)->remfd. + */ +LOCAL void rscsiabrt __PR((int sig)); +LOCAL int rscsigetconn __PR((SCSI *usalp, char *host)); +LOCAL char *rscsiversion __PR((SCSI *usalp, int fd, int what)); +LOCAL int rscsiopen __PR((SCSI *usalp, int fd, char *fname)); +LOCAL int rscsiclose __PR((SCSI *usalp, int fd)); +LOCAL int rscsimaxdma __PR((SCSI *usalp, int fd, long amt)); +LOCAL int rscsigetbuf __PR((SCSI *usalp, int fd, long amt)); +LOCAL int rscsifreebuf __PR((SCSI *usalp, int fd)); +LOCAL int rscsihavebus __PR((SCSI *usalp, int fd, int bus)); +LOCAL int rscsifileno __PR((SCSI *usalp, int fd, int busno, int tgt, int tlun)); +LOCAL int rscsiinitiator_id __PR((SCSI *usalp, int fd)); +LOCAL int rscsiisatapi __PR((SCSI *usalp, int fd)); +LOCAL int rscsireset __PR((SCSI *usalp, int fd, int what)); +LOCAL int rscsiscmd __PR((SCSI *usalp, int fd, struct usal_cmd *sp)); +LOCAL int rscsifillrbuf __PR((SCSI *usalp)); +LOCAL int rscsirchar __PR((SCSI *usalp, char *cp)); +LOCAL int rscsireadbuf __PR((SCSI *usalp, int fd, char *buf, int count)); +LOCAL void rscsivoidarg __PR((SCSI *usalp, int fd, int count)); +LOCAL int rscsicmd __PR((SCSI *usalp, int fd, char *name, char *cbuf)); +LOCAL void rscsisendcmd __PR((SCSI *usalp, int fd, char *name, char *cbuf)); +LOCAL int rscsigetline __PR((SCSI *usalp, int fd, char *line, int count)); +LOCAL int rscsireadnum __PR((SCSI *usalp, int fd)); +LOCAL int rscsigetstatus __PR((SCSI *usalp, int fd, char *name)); +LOCAL int rscsiaborted __PR((SCSI *usalp, int fd)); +#ifdef USE_RCMD_RSH +LOCAL int _rcmdrsh __PR((char **ahost, int inport, + const char *locuser, + const char *remuser, + const char *cmd, + const char *rsh)); +#ifdef HAVE_GETPPRIV +LOCAL BOOL ppriv_ok __PR((void)); +#endif +#endif + +/*--------------------------------------------------------------------------*/ + +#define READBUF_SIZE 128 + +struct usal_local { + int remfd; + char readbuf[READBUF_SIZE]; + char *readbptr; + int readbcnt; + BOOL isopen; + int rsize; + int wsize; + char *v_version; + char *v_author; + char *v_sccs_id; +}; + + +#define usallocal(p) ((struct usal_local *)((p)->local)) + +usal_ops_t remote_ops = { + usalo_rsend, /* "S" end */ + usalo_rversion, /* "V" ersion */ + usalo_rhelp, /* help */ + usalo_ropen, /* "O" pen */ + usalo_rclose, /* "C" lose */ + usalo_rmaxdma, /* "D" MA */ + usalo_rgetbuf, /* "M" alloc */ + usalo_rfreebuf, /* "F" free */ + usalo_rhavebus, /* "B" us */ + usalo_rfileno, /* "T" arget */ + usalo_rinitiator_id, /* "I" nitiator */ + usalo_risatapi, /* "A" tapi */ + usalo_rreset, /* "R" eset */ +}; + +/* + * Return our ops ptr. + */ +usal_ops_t * +usal_remote() +{ + return (&remote_ops); +} + +/* + * Return version information for the low level SCSI transport code. + * This has been introduced to make it easier to trace down problems + * in applications. + */ +LOCAL char * +usalo_rversion(usalp, what) + SCSI *usalp; + int what; +{ + int f; + + if (usalp->local == NULL) + return ((char *)0); + + f = usallocal(usalp)->remfd; + 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); + + case SCG_RVERSION: + if (usallocal(usalp)->v_version == NULL) + usallocal(usalp)->v_version = rscsiversion(usalp, f, SCG_VERSION); + return (usallocal(usalp)->v_version); + /* + * If you changed this source, you are not allowed to + * return "schily" for the SCG_AUTHOR request. + */ + case SCG_RAUTHOR: + if (usallocal(usalp)->v_author == NULL) + usallocal(usalp)->v_author = rscsiversion(usalp, f, SCG_AUTHOR); + return (usallocal(usalp)->v_author); + case SCG_RSCCS_ID: + if (usallocal(usalp)->v_sccs_id == NULL) + usallocal(usalp)->v_sccs_id = rscsiversion(usalp, f, SCG_SCCS_ID); + return (usallocal(usalp)->v_sccs_id); + } + } + return ((char *)0); +} + +LOCAL int +usalo_rhelp(usalp, f) + SCSI *usalp; + FILE *f; +{ + __usal_help(f, "RSCSI", "Remote SCSI", + "REMOTE:", "rscsi@host:bus,target,lun", "REMOTE:rscsi@host:1,2,0", TRUE, FALSE); + return (0); +} + +LOCAL int +usalo_ropen(usalp, device) + SCSI *usalp; + char *device; +{ + int busno = usal_scsibus(usalp); + int tgt = usal_target(usalp); + int tlun = usal_lun(usalp); + register int f; + register int nopen = 0; + char devname[128]; + char *p; + + if (usalp->overbose) + fprintf(stderr, "Warning: Using remote SCSI interface.\n"); + + 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 (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + usallocal(usalp)->remfd = -1; + usallocal(usalp)->readbptr = usallocal(usalp)->readbuf; + usallocal(usalp)->readbcnt = 0; + usallocal(usalp)->isopen = FALSE; + usallocal(usalp)->rsize = 0; + usallocal(usalp)->wsize = 0; + usallocal(usalp)->v_version = NULL; + usallocal(usalp)->v_author = NULL; + usallocal(usalp)->v_sccs_id = NULL; + } + + if (device == NULL || (strncmp(device, "REMOTE", 6) != 0) || + (device = strchr(device, ':')) == NULL) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Illegal remote device syntax"); + return (-1); + } + device++; + /* + * Save non user@host:device + */ + snprintf(devname, sizeof (devname), "%s", device); + + if ((p = strchr(devname, ':')) != NULL) + *p++ = '\0'; + + f = rscsigetconn(usalp, devname); + if (f < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot get connection to remote host"); + return (-1); + } + usallocal(usalp)->remfd = f; + debug = usalp->debug; + if (rscsiopen(usalp, f, p) >= 0) { + nopen++; + usallocal(usalp)->isopen = TRUE; + } + return (nopen); +} + +LOCAL int +usalo_rclose(usalp) + SCSI *usalp; +{ + register int f; + int ret; + + if (usalp->local == NULL) + return (-1); + + if (usallocal(usalp)->v_version != NULL) { + free(usallocal(usalp)->v_version); + usallocal(usalp)->v_version = NULL; + } + if (usallocal(usalp)->v_author != NULL) { + free(usallocal(usalp)->v_author); + usallocal(usalp)->v_author = NULL; + } + if (usallocal(usalp)->v_sccs_id != NULL) { + free(usallocal(usalp)->v_sccs_id); + usallocal(usalp)->v_sccs_id = NULL; + } + + f = usallocal(usalp)->remfd; + if (f < 0 || !usallocal(usalp)->isopen) + return (0); + ret = rscsiclose(usalp, f); + usallocal(usalp)->isopen = FALSE; + close(f); + usallocal(usalp)->remfd = -1; + return (ret); +} + +LOCAL long +usalo_rmaxdma(usalp, amt) + SCSI *usalp; + long amt; +{ + if (usalp->local == NULL) + return (-1L); + + return (rscsimaxdma(usalp, usallocal(usalp)->remfd, amt)); +} + +LOCAL void * +usalo_rgetbuf(usalp, amt) + SCSI *usalp; + long amt; +{ + int ret; + + if (usalp->local == NULL) + return ((void *)0); + + ret = rscsigetbuf(usalp, usallocal(usalp)->remfd, amt); + if (ret < 0) + return ((void *)0); + +#ifdef HAVE_VALLOC + usalp->bufbase = (void *)valloc((size_t)amt); +#else + usalp->bufbase = (void *)malloc((size_t)amt); +#endif + if (usalp->bufbase == NULL) { + usalo_rfreebuf(usalp); + return ((void *)0); + } + return (usalp->bufbase); +} + +LOCAL void +usalo_rfreebuf(usalp) + SCSI *usalp; +{ + int f; + + if (usalp->bufbase) + free(usalp->bufbase); + usalp->bufbase = NULL; + + if (usalp->local == NULL) + return; + + f = usallocal(usalp)->remfd; + if (f < 0 || !usallocal(usalp)->isopen) + return; + rscsifreebuf(usalp, f); +} + +LOCAL BOOL +usalo_rhavebus(usalp, busno) + SCSI *usalp; + int busno; +{ + if (usalp->local == NULL || busno < 0 || busno >= MAX_SCG) + return (FALSE); + + return (rscsihavebus(usalp, usallocal(usalp)->remfd, busno)); +} + +LOCAL int +usalo_rfileno(usalp, busno, tgt, tlun) + SCSI *usalp; + int busno; + int tgt; + int tlun; +{ + int f; + + if (usalp->local == NULL || + busno < 0 || busno >= MAX_SCG || + tgt < 0 || tgt >= MAX_TGT || + tlun < 0 || tlun >= MAX_LUN) + return (-1); + + f = usallocal(usalp)->remfd; + if (f < 0 || !usallocal(usalp)->isopen) + return (-1); + return (rscsifileno(usalp, f, busno, tgt, tlun)); +} + +LOCAL int +usalo_rinitiator_id(usalp) + SCSI *usalp; +{ + if (usalp->local == NULL) + return (-1); + + return (rscsiinitiator_id(usalp, usallocal(usalp)->remfd)); +} + +LOCAL int +usalo_risatapi(usalp) + SCSI *usalp; +{ + if (usalp->local == NULL) + return (-1); + + return (rscsiisatapi(usalp, usallocal(usalp)->remfd)); +} + +LOCAL int +usalo_rreset(usalp, what) + SCSI *usalp; + int what; +{ + if (usalp->local == NULL) + return (-1); + + return (rscsireset(usalp, usallocal(usalp)->remfd, what)); +} + +LOCAL int +usalo_rsend(usalp) + SCSI *usalp; +{ + struct usal_cmd *sp = usalp->scmd; + int ret; + + if (usalp->local == NULL) + return (-1); + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + ret = rscsiscmd(usalp, usallocal(usalp)->remfd, usalp->scmd); + + return (ret); +} + +/*--------------------------------------------------------------------------*/ +LOCAL void +rscsiabrt(sig) + int sig; +{ + rscsiaborted((SCSI *)0, -1); +} + +LOCAL int +rscsigetconn(usalp, host) + SCSI *usalp; + char *host; +{ + static struct servent *sp = 0; + static struct passwd *pw = 0; + char *name = "root"; + char *p; + char *rscsi; + char *rsh; + int rscsisock; + char *rscsipeer; + char rscsiuser[128]; + + + signal(SIGPIPE, rscsiabrt); + if (sp == 0) { + sp = getservbyname("shell", "tcp"); + if (sp == 0) { + comerrno(EX_BAD, "shell/tcp: unknown service\n"); + /* NOTREACHED */ + } + pw = getpwuid(getuid()); + if (pw == 0) { + comerrno(EX_BAD, "who are you? No passwd entry found.\n"); + /* NOTREACHED */ + } + } + if ((p = strchr(host, '@')) != NULL) { + size_t d = p - host; + + if (d > sizeof (rscsiuser)) + d = sizeof (rscsiuser); + snprintf(rscsiuser, sizeof (rscsiuser), "%.*s", (int)d, host); + name = rscsiuser; + host = &p[1]; + } else { + name = pw->pw_name; + } + if (usalp->debug > 0) + errmsgno(EX_BAD, "locuser: '%s' rscsiuser: '%s' host: '%s'\n", + pw->pw_name, name, host); + rscsipeer = host; + + if ((rscsi = getenv("RSCSI")) == NULL) + rscsi = "/usr/sbin/netscsid"; + rsh = getenv("RSH"); + +#ifdef USE_RCMD_RSH + if (!privport_ok() || rsh != NULL) + rscsisock = _rcmdrsh(&rscsipeer, (unsigned short)sp->s_port, + pw->pw_name, name, rscsi, rsh); + else +#endif +#ifdef HAVE_RCMD + rscsisock = rcmd(&rscsipeer, (unsigned short)sp->s_port, + pw->pw_name, name, rscsi, 0); +#else + rscsisock = _rcmdrsh(&rscsipeer, (unsigned short)sp->s_port, + pw->pw_name, name, rscsi, rsh); +#endif + + return (rscsisock); +} + +LOCAL char * +rscsiversion(usalp, fd, what) + SCSI *usalp; + int fd; + int what; +{ + char cbuf[CMD_SIZE]; + char *p; + int ret; + + snprintf(cbuf, sizeof (cbuf), "V%d\n", what); + ret = rscsicmd(usalp, fd, "version", cbuf); + p = malloc(ret); + if (p == NULL) + return (p); + rscsireadbuf(usalp, fd, p, ret); + return (p); +} + +LOCAL int +rscsiopen(usalp, fd, fname) + SCSI *usalp; + int fd; + char *fname; +{ + char cbuf[CMD_SIZE]; + int ret; + int bus; + int chan; + int tgt; + int lun; + + snprintf(cbuf, sizeof (cbuf), "O%s\n", fname?fname:""); + ret = rscsicmd(usalp, fd, "open", cbuf); + if (ret < 0) + return (ret); + + bus = rscsireadnum(usalp, fd); + chan = rscsireadnum(usalp, fd); + tgt = rscsireadnum(usalp, fd); + lun = rscsireadnum(usalp, fd); + + usal_settarget(usalp, bus, tgt, lun); + return (ret); +} + +LOCAL int +rscsiclose(usalp, fd) + SCSI *usalp; + int fd; +{ + return (rscsicmd(usalp, fd, "close", "C\n")); +} + +LOCAL int +rscsimaxdma(usalp, fd, amt) + SCSI *usalp; + int fd; + long amt; +{ + char cbuf[CMD_SIZE]; + + snprintf(cbuf, sizeof (cbuf), "D%ld\n", amt); + return (rscsicmd(usalp, fd, "maxdma", cbuf)); +} + +LOCAL int +rscsigetbuf(usalp, fd, amt) + SCSI *usalp; + int fd; + long amt; +{ + char cbuf[CMD_SIZE]; + int size; + int ret; + + snprintf(cbuf, sizeof (cbuf), "M%ld\n", amt); + ret = rscsicmd(usalp, fd, "getbuf", cbuf); + if (ret < 0) + return (ret); + + size = ret + 1024; /* Add protocol overhead */ + +#ifdef SO_SNDBUF + if (size > usallocal(usalp)->wsize) while (size > 512 && + setsockopt(fd, SOL_SOCKET, SO_SNDBUF, + (char *)&size, sizeof (size)) < 0) { + size -= 512; + } + if (size > usallocal(usalp)->wsize) { + usallocal(usalp)->wsize = size; + if (usalp->debug > 0) + errmsgno(EX_BAD, "sndsize: %d\n", size); + } +#endif +#ifdef SO_RCVBUF + if (size > usallocal(usalp)->rsize) while (size > 512 && + setsockopt(fd, SOL_SOCKET, SO_RCVBUF, + (char *)&size, sizeof (size)) < 0) { + size -= 512; + } + if (size > usallocal(usalp)->rsize) { + usallocal(usalp)->rsize = size; + if (usalp->debug > 0) + errmsgno(EX_BAD, "rcvsize: %d\n", size); + } +#endif + return (ret); +} + +LOCAL int +rscsifreebuf(usalp, fd) + SCSI *usalp; + int fd; +{ + return (rscsicmd(usalp, fd, "freebuf", "F\n")); +} + +LOCAL int +rscsihavebus(usalp, fd, busno) + SCSI *usalp; + int fd; + int busno; +{ + char cbuf[2*CMD_SIZE]; + + snprintf(cbuf, sizeof (cbuf), "B%d\n%d\n", + busno, + 0); + return (rscsicmd(usalp, fd, "havebus", cbuf)); +} + +LOCAL int +rscsifileno(usalp, fd, busno, tgt, tlun) + SCSI *usalp; + int fd; + int busno; + int tgt; + int tlun; +{ + char cbuf[3*CMD_SIZE]; + + snprintf(cbuf, sizeof (cbuf), "T%d\n%d\n%d\n%d\n", + busno, + 0, + tgt, + tlun); + return (rscsicmd(usalp, fd, "fileno", cbuf)); +} + +LOCAL int +rscsiinitiator_id(usalp, fd) + SCSI *usalp; + int fd; +{ + return (rscsicmd(usalp, fd, "initiator id", "I\n")); +} + +LOCAL int +rscsiisatapi(usalp, fd) + SCSI *usalp; + int fd; +{ + return (rscsicmd(usalp, fd, "isatapi", "A\n")); +} + +LOCAL int +rscsireset(usalp, fd, what) + SCSI *usalp; + int fd; + int what; +{ + char cbuf[CMD_SIZE]; + + snprintf(cbuf, sizeof (cbuf), "R%d\n", what); + return (rscsicmd(usalp, fd, "reset", cbuf)); +} + +LOCAL int +rscsiscmd(usalp, fd, sp) + SCSI *usalp; + int fd; + struct usal_cmd *sp; +{ + char cbuf[1600]; + int ret; + int amt = 0; + int voidsize = 0; + + ret = snprintf(cbuf, sizeof (cbuf), "S%d\n%d\n%d\n%d\n%d\n", + sp->size, sp->flags, + sp->cdb_len, sp->sense_len, + sp->timeout); + movebytes(sp->cdb.cmd_cdb, &cbuf[ret], sp->cdb_len); + ret += sp->cdb_len; + + if ((sp->flags & SCG_RECV_DATA) == 0 && sp->size > 0) { + amt = sp->size; + if ((ret + amt) <= sizeof (cbuf)) { + movebytes(sp->addr, &cbuf[ret], amt); + ret += amt; + amt = 0; + } + } + errno = 0; + if (_nixwrite(fd, cbuf, ret) != ret) + rscsiaborted(usalp, fd); + + if (amt > 0) { + if (_nixwrite(fd, sp->addr, amt) != amt) + rscsiaborted(usalp, fd); + } + + ret = rscsigetstatus(usalp, fd, "sendcmd"); + if (ret < 0) + return (ret); + + sp->resid = sp->size - ret; + sp->error = rscsireadnum(usalp, fd); + sp->ux_errno = rscsireadnum(usalp, fd); + *(Uchar *)&sp->scb = rscsireadnum(usalp, fd); + sp->sense_count = rscsireadnum(usalp, fd); + + if (sp->sense_count > SCG_MAX_SENSE) { + voidsize = sp->sense_count - SCG_MAX_SENSE; + sp->sense_count = SCG_MAX_SENSE; + } + if (sp->sense_count > 0) { + rscsireadbuf(usalp, fd, (char *)sp->u_sense.cmd_sense, sp->sense_count); + rscsivoidarg(usalp, fd, voidsize); + } + + if ((sp->flags & SCG_RECV_DATA) != 0 && ret > 0) + rscsireadbuf(usalp, fd, sp->addr, ret); + + return (0); +} + +LOCAL int +rscsifillrbuf(usalp) + SCSI *usalp; +{ + usallocal(usalp)->readbptr = usallocal(usalp)->readbuf; + + return (usallocal(usalp)->readbcnt = + _niread(usallocal(usalp)->remfd, + usallocal(usalp)->readbuf, READBUF_SIZE)); +} + +LOCAL int +rscsirchar(usalp, cp) + SCSI *usalp; + char *cp; +{ + if (--(usallocal(usalp)->readbcnt) < 0) { + if (rscsifillrbuf(usalp) <= 0) + return (usallocal(usalp)->readbcnt); + --(usallocal(usalp)->readbcnt); + } + *cp = *(usallocal(usalp)->readbptr)++; + return (1); +} + +LOCAL int +rscsireadbuf(usalp, fd, buf, count) + SCSI *usalp; + int fd; + char *buf; + int count; +{ + register int n = count; + register int amt = 0; + register int cnt; + + if (usallocal(usalp)->readbcnt > 0) { + cnt = usallocal(usalp)->readbcnt; + if (cnt > n) + cnt = n; + movebytes(usallocal(usalp)->readbptr, buf, cnt); + usallocal(usalp)->readbptr += cnt; + usallocal(usalp)->readbcnt -= cnt; + amt += cnt; + } + while (amt < n) { + if ((cnt = _niread(fd, &buf[amt], n - amt)) <= 0) { + return (rscsiaborted(usalp, fd)); + } + amt += cnt; + } + return (amt); +} + +LOCAL void +rscsivoidarg(usalp, fd, n) + SCSI *usalp; + int fd; + register int n; +{ + register int i; + register int amt; + char buf[512]; + + for (i = 0; i < n; i += amt) { + amt = sizeof (buf); + if ((n - i) < amt) + amt = n - i; + rscsireadbuf(usalp, fd, buf, amt); + } +} + +LOCAL int +rscsicmd(usalp, fd, name, cbuf) + SCSI *usalp; + int fd; + char *name; + char *cbuf; +{ + rscsisendcmd(usalp, fd, name, cbuf); + return (rscsigetstatus(usalp, fd, name)); +} + +LOCAL void +rscsisendcmd(usalp, fd, name, cbuf) + SCSI *usalp; + int fd; + char *name; + char *cbuf; +{ + int buflen = strlen(cbuf); + + errno = 0; + if (_nixwrite(fd, cbuf, buflen) != buflen) + rscsiaborted(usalp, fd); +} + +LOCAL int +rscsigetline(usalp, fd, line, count) + SCSI *usalp; + int fd; + char *line; + int count; +{ + register char *cp; + + for (cp = line; cp < &line[count]; cp++) { + if (rscsirchar(usalp, cp) != 1) + return (rscsiaborted(usalp, fd)); + + if (*cp == '\n') { + *cp = '\0'; + return (cp - line); + } + } + return (rscsiaborted(usalp, fd)); +} + +LOCAL int +rscsireadnum(usalp, fd) + SCSI *usalp; + int fd; +{ + char cbuf[CMD_SIZE]; + + rscsigetline(usalp, fd, cbuf, sizeof (cbuf)); + return (atoi(cbuf)); +} + +LOCAL int +rscsigetstatus(usalp, fd, name) + SCSI *usalp; + int fd; + char *name; +{ + char cbuf[CMD_SIZE]; + char code; + int number; + int count; + int voidsize = 0; + + rscsigetline(usalp, fd, cbuf, sizeof (cbuf)); + code = cbuf[0]; + number = atoi(&cbuf[1]); + + if (code == 'E' || code == 'F') { + rscsigetline(usalp, fd, cbuf, sizeof (cbuf)); + if (code == 'F') /* should close file ??? */ + rscsiaborted(usalp, fd); + + rscsigetline(usalp, fd, cbuf, sizeof (cbuf)); + count = atoi(cbuf); + if (count > 0) { + if (usalp->errstr == NULL) { + voidsize = count; + count = 0; + } else if (count > SCSI_ERRSTR_SIZE) { + voidsize = count - SCSI_ERRSTR_SIZE; + count = SCSI_ERRSTR_SIZE; + } + rscsireadbuf(usalp, fd, usalp->errstr, count); + rscsivoidarg(usalp, fd, voidsize); + } + if (usalp->debug > 0) + errmsgno(number, "Remote status(%s): %d '%s'.\n", + name, number, cbuf); + errno = number; + return (-1); + } + if (code != 'A') { + /* XXX Hier kommt evt Command not found ... */ + if (usalp->debug > 0) + errmsgno(EX_BAD, "Protocol error (got %s).\n", cbuf); + return (rscsiaborted(usalp, fd)); + } + return (number); +} + +LOCAL int +rscsiaborted(usalp, fd) + SCSI *usalp; + int fd; +{ + if ((usalp && usalp->debug > 0) || debug) + errmsgno(EX_BAD, "Lost connection to remote host ??\n"); + /* if fd >= 0 */ + /* close file */ + if (errno == 0) + errno = EIO; + return (-1); +} + +/*--------------------------------------------------------------------------*/ +#ifdef USE_RCMD_RSH +/* + * If we make a separate file for libschily, we would need these include files: + * + * socketpair(): sys/types.h + sys/socket.h + * dup2(): unixstd.h (hat auch sys/types.h) + * strrchr(): strdefs.h + * + * and make sure that we use sigset() instead of signal() if possible. + */ +#include <waitdefs.h> +LOCAL int +_rcmdrsh(ahost, inport, locuser, remuser, cmd, rsh) + char **ahost; + int inport; /* port is ignored */ + const char *locuser; + const char *remuser; + const char *cmd; + const char *rsh; +{ + struct passwd *pw; + int pp[2]; + int pid; + + if (rsh == 0) + rsh = "rsh"; + + /* + * Verify that 'locuser' is present on local host. + */ + if ((pw = getpwnam(locuser)) == NULL) { + errmsgno(EX_BAD, "Unknown user: %s\n", locuser); + return (-1); + } + /* XXX Check the existence for 'ahost' here? */ + + /* + * rcmd(3) creates a single socket to be used for communication. + * We need a bi-directional pipe to implement the same interface. + * On newer OS that implement bi-directional we could use pipe(2) + * but it makes no sense unless we find an OS that implements a + * bi-directional pipe(2) but no socketpair(). + */ + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pp) == -1) { + errmsg("Cannot create socketpair.\n"); + return (-1); + } + + pid = fork(); + if (pid < 0) { + return (-1); + } else if (pid == 0) { + const char *p; + const char *av0; + int xpid; + + (void) close(pp[0]); + if (dup2(pp[1], 0) == -1 || /* Pipe becomes 'stdin' */ + dup2(0, 1) == -1) { /* Pipe becomes 'stdout' */ + + errmsg("dup2 failed.\n"); + _exit(EX_BAD); + /* NOTREACHED */ + } + (void) close(pp[1]); /* We don't need this anymore*/ + + /* + * Become 'locuser' to tell the rsh program the local user id. + */ + if (getuid() != pw->pw_uid && + setuid(pw->pw_uid) == -1) { + errmsg("setuid(%lld) failed.\n", + (Llong)pw->pw_uid); + _exit(EX_BAD); + /* NOTREACHED */ + } + if (getuid() != geteuid() && +#ifdef HAVE_SETREUID + setreuid(-1, pw->pw_uid) == -1) { +#else +#ifdef HAVE_SETEUID + seteuid(pw->pw_uid) == -1) { +#else + setuid(pw->pw_uid) == -1) { +#endif +#endif + errmsg("seteuid(%lld) failed.\n", + (Llong)pw->pw_uid); + _exit(EX_BAD); + /* NOTREACHED */ + } + if (getuid() != geteuid() && + seteuid(pw->pw_uid) == -1) { + errmsg("seteuid(%lld) failed.\n", + (Llong)pw->pw_uid); + _exit(EX_BAD); + /* NOTREACHED */ + } + + /* + * Fork again to completely detach from parent + * and avoid the need to wait(2). + */ + if ((xpid = fork()) == -1) { + errmsg("rcmdsh: fork to lose parent failed.\n"); + _exit(EX_BAD); + /* NOTREACHED */ + } + if (xpid > 0) { + _exit(0); + /* NOTREACHED */ + } + + /* + * Always use remote shell programm (even for localhost). + * The client command may call getpeername() for security + * reasons and this would fail on a simple pipe. + */ + + + /* + * By default, 'rsh' handles terminal created signals + * but this is not what we like. + * For this reason, we tell 'rsh' to ignore these signals. + * Ignoring these signals is important to allow 'star' / 'sdd' + * to e.g. implement SIGQUIT as signal to trigger intermediate + * status printing. + * + * For now (late 2002), we know that the following programs + * are broken and do not implement signal handling correctly: + * + * rsh on SunOS-5.0...SunOS-5.9 + * ssh from ssh.com + * ssh from openssh.org + * + * Sun already did accept a bug report for 'rsh'. For the ssh + * commands we need to send out bug reports. Meanwhile it could + * help to call setsid() if we are running under X so the ssh + * X pop up for passwd reading will work. + */ + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); +#ifdef SIGTSTP + signal(SIGTSTP, SIG_IGN); /* We would not be able to continue*/ +#endif + + av0 = rsh; + if ((p = strrchr(rsh, '/')) != NULL) + av0 = ++p; + execlp(rsh, av0, *ahost, "-l", remuser, cmd, (char *)NULL); + + errmsg("execlp '%s' failed.\n", rsh); + _exit(EX_BAD); + /* NOTREACHED */ + } else { + (void) close(pp[1]); + /* + * Wait for the intermediate child. + * The real 'rsh' program is completely detached from us. + */ + wait(0); + return (pp[0]); + } + return (-1); /* keep gcc happy */ +} + +#ifdef HAVE_GETPPRIV +#include <priv.h> + +LOCAL BOOL +ppriv_ok() +{ + priv_set_t *privset; + BOOL net_privaddr = FALSE; + + + if ((privset = priv_allocset()) == NULL) { + return (FALSE); + } + if (getppriv(PRIV_EFFECTIVE, privset) == -1) { + priv_freeset(privset); + return (FALSE); + } + if (priv_ismember(privset, PRIV_NET_PRIVADDR)) { + net_privaddr = TRUE; + } + priv_freeset(privset); + + return (net_privaddr); +} +#endif /* HAVE_GETPPRIV */ + +#endif /* USE_RCMD_RSH */ + +#endif /* USE_REMOTE */ diff --git a/libusal/scsi-sgi.c b/libusal/scsi-sgi.c new file mode 100644 index 0000000..b19a3ae --- /dev/null +++ b/libusal/scsi-sgi.c @@ -0,0 +1,479 @@ +/* + * 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-sgi.c 1.36 04/01/15 Copyright 1997 J. Schilling */ +/* + * Interface for the SGI generic SCSI implementation. + * + * First Hacky implementation + * (needed libds, did not support bus scanning and had no error checking) + * from "Frank van Beek" <frank@neogeo.nl> + * + * Actual implementation supports all usal features. + * + * 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. + * + * Copyright (c) 1997 J. Schilling + */ +/* + * 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. + */ + +#include <dslib.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-sgi.c-1.36"; /* The version for this transport*/ + +#ifdef USE_DSLIB + +struct dsreq * dsp = 0; +#define MAX_SCG 1 /* Max # of SCSI controllers */ + +#else + +#define MAX_SCG 16 /* Max # of SCSI controllers */ +#define MAX_TGT 16 +#define MAX_LUN 8 + +struct usal_local { + short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN]; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +#endif + +#define MAX_DMA_SGI (256*1024) /* Check if this is not too big */ + + +#ifndef USE_DSLIB +static int usal_sendreq(SCSI *usalp, struct usal_cmd *sp, struct dsreq *dsp); +#endif + + +/* + * 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, "DS", "Generic 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); + register int f; + register int b; + register int t; + register int l; + register int nopen = 0; + char devname[64]; + + 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); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } + + if (busno >= 0 && tgt >= 0 && tlun >= 0) { + + snprintf(devname, sizeof (devname), + "/dev/scsi/sc%dd%dl%d", busno, tgt, tlun); +#ifdef USE_DSLIB + dsp = dsopen(devname, O_RDWR); + if (dsp == 0) + return (-1); +#else + f = open(devname, O_RDWR); + if (f < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", + devname); + return (-1); + } + usallocal(usalp)->usalfiles[busno][tgt][tlun] = f; +#endif + return (1); + } else { +#ifdef USE_DSLIB + return (-1); +#else + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { +/* for (l = 0; l < MAX_LUN; l++) {*/ + for (l = 0; l < 1; l++) { + snprintf(devname, sizeof (devname), + "/dev/scsi/sc%dd%dl%d", b, t, l); + f = open(devname, O_RDWR); + if (f >= 0) { + usallocal(usalp)->usalfiles[b][t][l] = (short)f; + nopen++; + } + } + } + } +#endif + } + return (nopen); +} + +static int +usalo_close(SCSI *usalp) +{ +#ifndef USE_DSLIB + register int f; + register int b; + register int t; + register int l; + + if (usalp->local == NULL) + return (-1); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + f = usallocal(usalp)->usalfiles[b][t][l]; + if (f >= 0) + close(f); + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } +#else + dsclose(dsp); +#endif + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + return (MAX_DMA_SGI); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = valloc((size_t)(amt)); + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + 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); + + if (usalp->local == NULL) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if (usallocal(usalp)->usalfiles[busno][t][l] >= 0) + return (TRUE); + } + return (FALSE); +} + +static int +usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun) +{ +#ifdef USE_DSLIB + if (dsp == NULL) + return (-1); + return (getfd(dsp)); +#else + if (busno < 0 || busno >= MAX_SCG || + tgt < 0 || tgt >= MAX_TGT || + tlun < 0 || tlun >= MAX_LUN) + return (-1); + + if (usalp->local == NULL) + return (-1); + + return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]); +#endif +} + +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) +{ + /* + * Do we have a SCSI reset on SGI? + */ +#ifdef DS_RESET + if (what == SCG_RESET_NOP) + return (0); + if (what != SCG_RESET_BUS) { + errno = EINVAL; + return (-1); + } + /* + * XXX Does this reset TGT or BUS ??? + */ + return (ioctl(usalp->fd, DS_RESET, 0)); +#else + return (-1); +#endif +} + +#ifndef USE_DSLIB +static int +usal_sendreq(SCSI *usalp, struct usal_cmd *sp, struct dsreq *dsp) +{ + int ret; + int retries = 4; + Uchar status; + +/* if ((sp->flags & SCG_CMD_RETRY) == 0)*/ +/* retries = 0;*/ + + while (--retries > 0) { + ret = ioctl(usalp->fd, DS_ENTER, dsp); + if (ret < 0) { + RET(dsp) = DSRT_DEVSCSI; + return (-1); + } + /* + * SGI implementattion botch!!! + * If a target does not select the bus, + * the return code is DSRT_TIMEOUT + */ + if (RET(dsp) == DSRT_TIMEOUT) { + struct timeval to; + + to.tv_sec = TIME(dsp)/1000; + to.tv_usec = TIME(dsp)%1000; + __usal_times(usalp); + + if (sp->cdb.g0_cdb.cmd == SC_TEST_UNIT_READY && + usalp->cmdstop->tv_sec < to.tv_sec || + (usalp->cmdstop->tv_sec == to.tv_sec && + usalp->cmdstop->tv_usec < to.tv_usec)) { + + RET(dsp) = DSRT_NOSEL; + return (-1); + } + } + if (RET(dsp) == DSRT_NOSEL) + continue; /* retry noselect 3X */ + + status = STATUS(dsp); + switch (status) { + + case 0x08: /* BUSY */ + case 0x18: /* RESERV CONFLICT */ + if (retries > 0) + sleep(2); + continue; + case 0x00: /* GOOD */ + case 0x02: /* CHECK CONDITION */ + case 0x10: /* INTERM/GOOD */ + default: + return (status); + } + } + return (-1); /* failed retry limit */ +} +#endif + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + int ret; + int i; + int amt = sp->cdb_len; + int flags; +#ifndef USE_DSLIB + struct dsreq ds; + struct dsreq *dsp = &ds; + + dsp->ds_iovbuf = 0; + dsp->ds_iovlen = 0; +#endif + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + + flags = DSRQ_SENSE; + if (sp->flags & SCG_RECV_DATA) + flags |= DSRQ_READ; + else if (sp->size > 0) + flags |= DSRQ_WRITE; + + dsp->ds_flags = flags; + dsp->ds_link = 0; + dsp->ds_synch = 0; + dsp->ds_ret = 0; + + DATABUF(dsp) = sp->addr; + DATALEN(dsp) = sp->size; + CMDBUF(dsp) = (void *) &sp->cdb; + CMDLEN(dsp) = sp->cdb_len; + SENSEBUF(dsp) = (caddr_t)sp->u_sense.cmd_sense; + SENSELEN(dsp) = sizeof (sp->u_sense.cmd_sense); + TIME(dsp) = (sp->timeout * 1000) + 100; + + errno = 0; + sp->ux_errno = 0; + sp->sense_count = 0; + +#ifdef USE_DSLIB + ret = doscsireq(usalp->fd, dsp); +#else + ret = usal_sendreq(usalp, sp, dsp); +#endif + + if (RET(dsp) != DSRT_DEVSCSI) + ret = 0; + + if (RET(dsp)) { + if (RET(dsp) == DSRT_SHORT) { + sp->resid = DATALEN(dsp)- DATASENT(dsp); + } else if (errno) { + sp->ux_errno = errno; + } else { + sp->ux_errno = EIO; + } + + sp->u_scb.cmd_scb[0] = STATUS(dsp); + + sp->sense_count = SENSESENT(dsp); + if (sp->sense_count > SCG_MAX_SENSE) + sp->sense_count = SCG_MAX_SENSE; + + } + switch (RET(dsp)) { + + default: + sp->error = SCG_RETRYABLE; break; + + case 0: /* OK */ + case DSRT_SHORT: /* not implemented */ + sp->error = SCG_NO_ERROR; break; + + case DSRT_UNIMPL: /* not implemented */ + case DSRT_REVCODE: /* software obsolete must recompile */ + case DSRT_NOSEL: + sp->u_scb.cmd_scb[0] = 0; + sp->error = SCG_FATAL; break; + + case DSRT_TIMEOUT: + sp->u_scb.cmd_scb[0] = 0; + sp->error = SCG_TIMEOUT; break; + } + return (ret); +} diff --git a/libusal/scsi-sun.c b/libusal/scsi-sun.c new file mode 100644 index 0000000..9ea8da8 --- /dev/null +++ b/libusal/scsi-sun.c @@ -0,0 +1,1133 @@ +/* + * 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-sun.c 1.83 05/11/20 Copyright 1988,1995,2000-2004 J. Schilling */ +/* + * SCSI user level command transport routines for + * the SCSI general driver 'usal'. + * + * 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. + * + * Copyright (c) 1988,1995,2000-2004 J. Schilling + */ +/* + * 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. + */ + +#include <usal/usalio.h> + +#include <libport.h> /* Needed for gethostid() */ +#ifdef HAVE_SUN_DKIO_H +# include <sun/dkio.h> + +# define dk_cinfo dk_conf +# define dki_slave dkc_slave +# define DKIO_GETCINFO DKIOCGCONF +#endif +#ifdef HAVE_SYS_DKIO_H +# include <sys/dkio.h> + +# define DKIO_GETCINFO DKIOCINFO +#endif + +#define TARGET(slave) ((slave) >> 3) +#define LUN(slave) ((slave) & 07) + +/* + * Tht USCSI ioctl() is not usable on SunOS 4.x + */ +#ifdef __SVR4 +/*#define VOLMGT_DEBUG*/ +#include <volmgt.h> +#include <statdefs.h> +# define USE_USCSI +#endif + +static char _usal_trans_version[] = "usal-1.83"; /* The version for /dev/usal */ +static char _usal_utrans_version[] = "uscsi-1.83"; /* The version for USCSI */ + +#ifdef USE_USCSI +static int usalo_uhelp(SCSI *usalp, FILE *f); +static int usalo_uopen(SCSI *usalp, char *device); +static int usalo_volopen(SCSI *usalp, char *devname); +static int usalo_openmedia(SCSI *usalp, char *mname); +static int usalo_uclose(SCSI *usalp); +static int usalo_ucinfo(int f, struct dk_cinfo *cp, int debug); +static int usalo_ugettlun(int f, int *tgtp, int *lunp); +static long usalo_umaxdma(SCSI *usalp, long amt); +static int usalo_openide(void); +static BOOL usalo_uhavebus(SCSI *usalp, int); +static int usalo_ufileno(SCSI *usalp, int, int, int); +static int usalo_uinitiator_id(SCSI *usalp); +static int usalo_uisatapi(SCSI *usalp); +static int usalo_ureset(SCSI *usalp, int what); +static int usalo_usend(SCSI *usalp); + +static int have_volmgt = -1; + +static usal_ops_t sun_uscsi_ops = { + usalo_usend, + usalo_version, /* Shared with SCG driver */ + usalo_uhelp, + usalo_uopen, + usalo_uclose, + usalo_umaxdma, + usalo_getbuf, /* Shared with SCG driver */ + usalo_freebuf, /* Shared with SCG driver */ + usalo_uhavebus, + usalo_ufileno, + usalo_uinitiator_id, + usalo_uisatapi, + usalo_ureset, +}; +#endif + +/* + * Need to move this into an usal driver ioctl. + */ +/*#define MAX_DMA_SUN4M (1024*1024)*/ +#define MAX_DMA_SUN4M (124*1024) /* Currently max working size */ +/*#define MAX_DMA_SUN4C (126*1024)*/ +#define MAX_DMA_SUN4C (124*1024) /* Currently max working size */ +#define MAX_DMA_SUN3 (63*1024) +#define MAX_DMA_SUN386 (56*1024) +#define MAX_DMA_OTHER (32*1024) + +#define ARCH_MASK 0xF0 +#define ARCH_SUN2 0x00 +#define ARCH_SUN3 0x10 +#define ARCH_SUN4 0x20 +#define ARCH_SUN386 0x30 +#define ARCH_SUN3X 0x40 +#define ARCH_SUN4C 0x50 +#define ARCH_SUN4E 0x60 +#define ARCH_SUN4M 0x70 +#define ARCH_SUNX 0x80 + +/* + * We are using a "real" /dev/usal? + */ +#define scsi_xsend(usalp) ioctl((usalp)->fd, SCGIO_CMD, (usalp)->scmd) +#define MAX_SCG 16 /* Max # of SCSI controllers */ +#define MAX_TGT 16 +#define MAX_LUN 8 + +struct usal_local { + union { + int SCG_files[MAX_SCG]; +#ifdef USE_USCSI + short usal_files[MAX_SCG][MAX_TGT][MAX_LUN]; +#endif + } u; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) +#define usalfiles(p) (usallocal(p)->u.SCG_files) + +/* + * 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: +#ifdef USE_USCSI + if (usalp->ops == &sun_uscsi_ops) + return (_usal_utrans_version); +#endif + 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, "usal", "Generic transport independent SCSI", + "", "bus,target,lun", "1,2,0", TRUE, FALSE); +#ifdef USE_USCSI + usalo_uhelp(usalp, f); +#endif + 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);*/ + register int f; + register int i; + register int nopen = 0; + char devname[32]; + + if (busno >= MAX_SCG) { + errno = EINVAL; + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Illegal value for busno '%d'", busno); + return (-1); + } + + if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) { +#ifdef USE_USCSI + usalp->ops = &sun_uscsi_ops; + return (SCGO_OPEN(usalp, device)); +#else + errno = EINVAL; + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Open by 'devname' not supported on this OS"); + return (-1); +#endif + } + + if (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, "No memory for usal_local"); + return (0); + } + + for (i = 0; i < MAX_SCG; i++) { + usalfiles(usalp)[i] = -1; + } + } + + + for (i = 0; i < MAX_SCG; i++) { + /* + * Skip unneeded devices if not in SCSI Bus scan open mode + */ + if (busno >= 0 && busno != i) + continue; + snprintf(devname, sizeof (devname), "/dev/usal%d", i); + f = open(devname, O_RDWR); + if (f < 0) { + if (errno != ENOENT && errno != ENXIO) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Cannot open '%s'", devname); + return (-1); + } + } else { + nopen++; + } + usalfiles(usalp)[i] = f; + } +#ifdef USE_USCSI + if (nopen <= 0) { + if (usalp->local != NULL) { + free(usalp->local); + usalp->local = NULL; + } + usalp->ops = &sun_uscsi_ops; + return (SCGO_OPEN(usalp, device)); + } +#endif + return (nopen); +} + +static int +usalo_close(SCSI *usalp) +{ + register int i; + + if (usalp->local == NULL) + return (-1); + + for (i = 0; i < MAX_SCG; i++) { + if (usalfiles(usalp)[i] >= 0) + close(usalfiles(usalp)[i]); + usalfiles(usalp)[i] = -1; + } + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + long maxdma = MAX_DMA_OTHER; +#if !defined(__i386_) && !defined(i386) + int cpu_type; +#endif + +#if defined(__i386_) || defined(i386) + maxdma = MAX_DMA_SUN386; +#else + cpu_type = gethostid() >> 24; + + switch (cpu_type & ARCH_MASK) { + + case ARCH_SUN4C: + case ARCH_SUN4E: + maxdma = MAX_DMA_SUN4C; + break; + + case ARCH_SUN4M: + case ARCH_SUNX: + maxdma = MAX_DMA_SUN4M; + break; + + default: + maxdma = MAX_DMA_SUN3; + } +#endif + +#ifndef __SVR4 + /* + * SunOS 4.x allows esp hardware on VME boards and thus + * limits DMA on esp to 64k-1 + */ + if (maxdma > MAX_DMA_SUN3) + maxdma = MAX_DMA_SUN3; +#endif + return (maxdma); +} + +static BOOL +usalo_havebus(SCSI *usalp, int busno) +{ + if (usalp->local == NULL) + return (FALSE); + + return (busno < 0 || busno >= MAX_SCG) ? FALSE : (usalfiles(usalp)[busno] >= 0); +} + +static int +usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun) +{ + if (usalp->local == NULL) + return (-1); + + return ((busno < 0 || busno >= MAX_SCG) ? -1 : usalfiles(usalp)[busno]); +} + +static int +usalo_initiator_id(SCSI *usalp) +{ + int id = -1; +#ifdef DKIO_GETCINFO + struct dk_cinfo conf; +#endif + +#ifdef DKIO_GETCINFO + if (usalp->fd < 0) + return (id); + if (ioctl(usalp->fd, DKIO_GETCINFO, &conf) < 0) + return (id); + if (TARGET(conf.dki_slave) != -1) + id = TARGET(conf.dki_slave); +#endif + return (id); +} + +static int +usalo_isatapi(SCSI *usalp) +{ + return (FALSE); +} + +static int +usalo_reset(SCSI *usalp, int what) +{ + if (what == SCG_RESET_NOP) + return (0); + if (what != SCG_RESET_BUS) { + errno = EINVAL; + return (-1); + } + return (ioctl(usalp->fd, SCGIORESET, 0)); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + usalp->bufbase = (void *)valloc((size_t)amt); + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + usalp->bufbase = NULL; +} + +static int +usalo_send(SCSI *usalp) +{ + usalp->scmd->target = usal_target(usalp); + return (ioctl(usalp->fd, SCGIO_CMD, usalp->scmd)); +} + +/*--------------------------------------------------------------------------*/ +/* + * This is Sun USCSI interface code ... + */ +#ifdef USE_USCSI +#include <sys/scsi/impl/uscsi.h> + +/* + * Bit Mask definitions, for use accessing the status as a byte. + */ +#define STATUS_MASK 0x3E +#define STATUS_GOOD 0x00 +#define STATUS_CHECK 0x02 + +#define STATUS_RESERVATION_CONFLICT 0x18 +#define STATUS_TERMINATED 0x22 + +#ifdef nonono +#define STATUS_MASK 0x3E +#define STATUS_GOOD 0x00 +#define STATUS_CHECK 0x02 + +#define STATUS_MET 0x04 +#define STATUS_BUSY 0x08 +#define STATUS_INTERMEDIATE 0x10 +#define STATUS_SCSI2 0x20 +#define STATUS_INTERMEDIATE_MET 0x14 +#define STATUS_RESERVATION_CONFLICT 0x18 +#define STATUS_TERMINATED 0x22 +#define STATUS_QFULL 0x28 +#define STATUS_ACA_ACTIVE 0x30 +#endif + +static int +usalo_uhelp(SCSI *usalp, FILE *f) +{ + __usal_help(f, "USCSI", "SCSI transport for targets known by Solaris drivers", + "USCSI:", "bus,target,lun", "USCSI:1,2,0", TRUE, TRUE); + return (0); +} + +static int +usalo_uopen(SCSI *usalp, char *device) +{ + int busno = usal_scsibus(usalp); + int tgt = usal_target(usalp); + int tlun = usal_lun(usalp); + register int f; + register int b; + register int t; + register int l; + register int nopen = 0; + char devname[32]; + + if (have_volmgt < 0) + have_volmgt = volmgt_running(); + + if (usalp->overbose) { + fprintf((FILE *)usalp->errfile, + "Warning: Using USCSI interface.\n"); + } +#ifndef SEEK_HOLE + /* + * SEEK_HOLE first appears in Solaris 11 Build 14, volmgt supports + * medialess drives since Build 21. Using SEEK_HOLD as indicator + * seems to be the best guess. + */ + if (usalp->overbose > 0 && have_volmgt) { + fprintf((FILE *)usalp->errfile, + "Warning: Volume management is running, medialess managed drives are invisible.\n"); + } +#endif + + 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 (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, "No memory for usal_local"); + return (0); + } + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + usallocal(usalp)->u.usal_files[b][t][l] = (short)-1; + } + } + } + + if (device != NULL && strcmp(device, "USCSI") == 0) + goto uscsiscan; + + if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) + goto openbydev; + +uscsiscan: + if (busno >= 0 && tgt >= 0 && tlun >= 0) { + + if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) + return (-1); + + snprintf(devname, sizeof (devname), "/dev/rdsk/c%dt%dd%ds2", + busno, tgt, tlun); + f = open(devname, O_RDONLY | O_NDELAY); + if (f < 0 && geterrno() == EBUSY) + f = usalo_volopen(usalp, devname); + if (f < 0) { + snprintf(usalp->errstr, + SCSI_ERRSTR_SIZE, + "Cannot open '%s'", devname); + return (0); + } + usallocal(usalp)->u.usal_files[busno][tgt][tlun] = f; + return (1); + } else { + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + snprintf(devname, sizeof (devname), + "/dev/rdsk/c%dt%dd%ds2", + b, t, l); + f = open(devname, O_RDONLY | O_NDELAY); + if (f < 0 && geterrno() == EBUSY) { + f = usalo_volopen(usalp, devname); + /* + * Hack to mark inaccessible + * drives with fd == -2 + */ + if (f < 0 && + usallocal(usalp)->u.usal_files[b][t][l] < 0) + usallocal(usalp)->u.usal_files[b][t][l] = f; + } + if (f < 0 && errno != ENOENT && + errno != ENXIO && + errno != ENODEV) { + if (usalp->errstr) + snprintf(usalp->errstr, + SCSI_ERRSTR_SIZE, + "Cannot open '%s'", devname); + } + if (f < 0 && l == 0) + break; + if (f >= 0) { + nopen ++; + if (usallocal(usalp)->u.usal_files[b][t][l] == -1) + usallocal(usalp)->u.usal_files[b][t][l] = f; + else + close(f); + } + } + } + } + } +openbydev: + if (nopen == 0) { + int target; + int lun; + + if (device != NULL && strncmp(device, "USCSI:", 6) == 0) + device += 6; + if (device == NULL || device[0] == '\0') + return (0); + + f = open(device, O_RDONLY | O_NDELAY); + if (f < 0) + f = usalo_volopen(usalp, device); + if (f < 0) { + snprintf(usalp->errstr, + SCSI_ERRSTR_SIZE, + "Cannot open '%s'", device); + return (0); + } + + if (busno < 0) + busno = 0; /* Use Fake number if not specified */ + + if (usalo_ugettlun(f, &target, &lun) >= 0) { + if (tgt >= 0 && tlun >= 0) { + if (tgt != target || tlun != lun) { + close(f); + return (0); + } + } + tgt = target; + tlun = lun; + } else { + if (tgt < 0 || tlun < 0) { + close(f); + return (0); + } + } + + if (usallocal(usalp)->u.usal_files[busno][tgt][tlun] == -1) + usallocal(usalp)->u.usal_files[busno][tgt][tlun] = f; + usal_settarget(usalp, busno, tgt, tlun); + + return (++nopen); + } + return (nopen); +} + +static int +usalo_volopen(SCSI *usalp, char *devname) +{ + int oerr = geterrno(); + int f = -1; + char *name = NULL; /* Volume symbolic device name */ + char *symdev = NULL; /* /dev/... name based on "name" */ + char *mname = NULL; /* Volume media name based on "name" */ + + if (!have_volmgt) + return (-1); + +#ifdef VOLMGT_DEBUG + usalp->debug++; +#endif + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_volopen(%s)\n", devname); + } + + /* + * We come here because trying to open "devname" did not work. + * First try to translate between a symbolic name and a /dev/... + * based device name. Then translate back to a symbolic name. + */ + symdev = volmgt_symdev(devname); + if (symdev) + name = volmgt_symname(symdev); + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "volmgt_symdev(%s)=%s -> %s\n", devname, symdev, name); + } + + /* + * If "devname" is not a symbolic device name, then it must be + * a /dev/... based device name. Try to translate it into a + * symbolic name. Then translate back to a /dev/... name. + */ + if (name == NULL) { + name = volmgt_symname(devname); + if (name) + symdev = volmgt_symdev(name); + } + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "volmgt_symdev(%s)=%s -> %s\n", devname, symdev, name); + } + + /* + * If we have been able to translate to a symbolic device name, + * translate this name into a volume management media name that + * may be used for opening. + */ + if (name) + mname = media_findname(name); + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "symdev %s name %s mname %s\n", symdev, name, mname); + } + + /* + * Das scheint nur mit dem normierten /dev/rdsk/ *s2 Namen zu gehen. + */ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "volmgt_inuse(%s) %d\n", symdev, volmgt_inuse(symdev)); + } + if (mname) + f = usalo_openmedia(usalp, mname); + else if (name) + f = -2; /* Mark inaccessible drives with fd == -2 */ + + /* + * Besonderen Fehlertext oder fprintf/errfile bei non-scanbus Open und + * wenn errrno == EBUSY && kein Mapping? + */ + if (name) + free(name); + if (symdev) + free(symdev); + if (mname) + free(mname); + seterrno(oerr); +#ifdef VOLMGT_DEBUG + usalp->debug--; +#endif + return (f); +} + +static int +usalo_openmedia(SCSI *usalp, char *mname) +{ + int f = -1; + char *device = NULL; + struct stat sb; + + if (mname == NULL) + return (-1); + + /* + * Check whether the media name refers to a directory. + * In this case, the medium is partitioned and we need to + * check all partitions. + */ + if (stat(mname, &sb) >= 0) { + if (S_ISDIR(sb.st_mode)) { + char name[128]; + int i; + + /* + * First check partition '2', the whole disk. + */ + snprintf(name, sizeof (name), "%s/s2", mname); + f = open(name, O_RDONLY | O_NDELAY); + if (f >= 0) + return (f); + /* + * Now try all other partitions. + */ + for (i = 0; i < 16; i++) { + if (i == 2) + continue; + snprintf(name, sizeof (name), + "%s/s%d", mname, i); + if (stat(name, &sb) >= 0) + break; + } + if (i < 16) { + device = mname; + } + } else { + device = mname; + } + } + if (device) + f = open(device, O_RDONLY | O_NDELAY); + return (f); +} + +static int +usalo_uclose(SCSI *usalp) +{ + register int f; + register int b; + register int t; + register int l; + + if (usalp->local == NULL) + return (-1); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + f = usallocal(usalp)->u.usal_files[b][t][l]; + if (f >= 0) + close(f); + usallocal(usalp)->u.usal_files[b][t][l] = (short)-1; + } + } + } + return (0); +} + +static int +usalo_ucinfo(int f, struct dk_cinfo *cp, int debug) +{ + fillbytes(cp, sizeof (*cp), '\0'); + + if (ioctl(f, DKIOCINFO, cp) < 0) + return (-1); + + if (debug <= 0) + return (0); + + fprintf(stderr, "cname: '%s'\n", cp->dki_cname); + fprintf(stderr, "ctype: 0x%04hX %hd\n", cp->dki_ctype, cp->dki_ctype); + fprintf(stderr, "cflags: 0x%04hX\n", cp->dki_flags); + fprintf(stderr, "cnum: %hd\n", cp->dki_cnum); +#ifdef __EVER__ + fprintf(stderr, "addr: %d\n", cp->dki_addr); + fprintf(stderr, "space: %d\n", cp->dki_space); + fprintf(stderr, "prio: %d\n", cp->dki_prio); + fprintf(stderr, "vec: %d\n", cp->dki_vec); +#endif + fprintf(stderr, "dname: '%s'\n", cp->dki_dname); + fprintf(stderr, "unit: %d\n", cp->dki_unit); + fprintf(stderr, "slave: %d %04o Tgt: %d Lun: %d\n", + cp->dki_slave, cp->dki_slave, + TARGET(cp->dki_slave), LUN(cp->dki_slave)); + fprintf(stderr, "partition: %hd\n", cp->dki_partition); + fprintf(stderr, "maxtransfer: %d (%d)\n", + cp->dki_maxtransfer, + cp->dki_maxtransfer * DEV_BSIZE); + return (0); +} + +static int +usalo_ugettlun(int f, int *tgtp, int *lunp) +{ + struct dk_cinfo ci; + + if (usalo_ucinfo(f, &ci, 0) < 0) + return (-1); + if (tgtp) + *tgtp = TARGET(ci.dki_slave); + if (lunp) + *lunp = LUN(ci.dki_slave); + return (0); +} + +static long +usalo_umaxdma(SCSI *usalp, long amt) +{ + register int b; + register int t; + register int l; + long maxdma = -1L; + int f; + struct dk_cinfo ci; + BOOL found_ide = FALSE; + + if (usalp->local == NULL) + return (-1L); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + if ((f = usallocal(usalp)->u.usal_files[b][t][l]) < 0) + continue; + if (usalo_ucinfo(f, &ci, usalp->debug) < 0) + continue; + if (maxdma < 0) + maxdma = (long)(ci.dki_maxtransfer * DEV_BSIZE); + if (maxdma > (long)(ci.dki_maxtransfer * DEV_BSIZE)) + maxdma = (long)(ci.dki_maxtransfer * DEV_BSIZE); + if (streql(ci.dki_cname, "ide")) + found_ide = TRUE; + } + } + } + +#if defined(__i386_) || defined(i386) + /* + * At least on Solaris 9 x86, DKIOCINFO returns a wrong value + * for dki_maxtransfer if the target is an ATAPI drive. + * Without DMA, it seems to work if we use 256 kB DMA size for ATAPI, + * but if we allow DMA, only 68 kB will work (for more we get a silent + * DMA residual count == DMA transfer count). + * For this reason, we try to figure out the correct value for 'ide' + * by retrieving the (correct) value from a ide hard disk. + */ + if (found_ide) { + if ((f = usalo_openide()) >= 0) { +#ifdef sould_we + long omaxdma = maxdma; +#endif + + if (usalo_ucinfo(f, &ci, usalp->debug) >= 0) { + if (maxdma < 0) + maxdma = (long)(ci.dki_maxtransfer * DEV_BSIZE); + if (maxdma > (long)(ci.dki_maxtransfer * DEV_BSIZE)) + maxdma = (long)(ci.dki_maxtransfer * DEV_BSIZE); + } + close(f); +#ifdef sould_we + /* + * The kernel returns 56 kB but we tested that 68 kB works. + */ + if (omaxdma > maxdma && maxdma == (112 * DEV_BSIZE)) + maxdma = 136 * DEV_BSIZE; +#endif + } else { + /* + * No IDE disk on this system? + */ + if (maxdma == (512 * DEV_BSIZE)) + maxdma = MAX_DMA_SUN386; + } + } +#endif + /* + * The Sun tape driver does not support to retrieve the max DMA count. + * Use the knwoledge about default DMA sizes in this case. + */ + if (maxdma < 0) + maxdma = usalo_maxdma(usalp, amt); + + return (maxdma); +} + +#if defined(__i386_) || defined(i386) +static int +usalo_openide() +{ + char buf[20]; + int b; + int t; + int f = -1; + + for (b = 0; b < 5; b++) { + for (t = 0; t < 2; t++) { + snprintf(buf, sizeof (buf), + "/dev/rdsk/c%dd%dp0", b, t); + if ((f = open(buf, O_RDONLY | O_NDELAY)) >= 0) + goto out; + } + } +out: + return (f); +} +#endif + +static BOOL +usalo_uhavebus(SCSI *usalp, int busno) +{ + register int t; + register int l; + + if (usalp->local == NULL || busno < 0 || busno >= MAX_SCG) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if (usallocal(usalp)->u.usal_files[busno][t][l] >= 0) + return (TRUE); + } + return (FALSE); +} + +static int +usalo_ufileno(SCSI *usalp, int busno, int tgt, int tlun) +{ + if (usalp->local == NULL || + busno < 0 || busno >= MAX_SCG || + tgt < 0 || tgt >= MAX_TGT || + tlun < 0 || tlun >= MAX_LUN) + return (-1); + + return ((int)usallocal(usalp)->u.usal_files[busno][tgt][tlun]); +} + +static int +usalo_uinitiator_id(SCSI *usalp) +{ + return (-1); +} + +static int +usalo_uisatapi(SCSI *usalp) +{ + char devname[32]; + char symlinkname[MAXPATHLEN]; + int len; + struct dk_cinfo ci; + + if (ioctl(usalp->fd, DKIOCINFO, &ci) < 0) + return (-1); + + snprintf(devname, sizeof (devname), "/dev/rdsk/c%dt%dd%ds2", + usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp)); + + symlinkname[0] = '\0'; + len = readlink(devname, symlinkname, sizeof (symlinkname)); + if (len > 0) + symlinkname[len] = '\0'; + + if (len >= 0 && strstr(symlinkname, "ide") != NULL) + return (TRUE); + else + return (FALSE); +} + +static int +usalo_ureset(SCSI *usalp, int what) +{ + struct uscsi_cmd req; + + if (what == SCG_RESET_NOP) + return (0); + + fillbytes(&req, sizeof (req), '\0'); + + if (what == SCG_RESET_TGT) { + req.uscsi_flags = USCSI_RESET | USCSI_SILENT; /* reset target */ + } else if (what != SCG_RESET_BUS) { + req.uscsi_flags = USCSI_RESET_ALL | USCSI_SILENT; /* reset bus */ + } else { + errno = EINVAL; + return (-1); + } + + return (ioctl(usalp->fd, USCSICMD, &req)); +} + +static int +usalo_usend(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + struct uscsi_cmd req; + int ret; +static uid_t cureuid = 0; /* XXX Hack until we have uid management */ + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + + fillbytes(&req, sizeof (req), '\0'); + + req.uscsi_flags = USCSI_SILENT | USCSI_DIAGNOSE | USCSI_RQENABLE; + + if (sp->flags & SCG_RECV_DATA) { + req.uscsi_flags |= USCSI_READ; + } else if (sp->size > 0) { + req.uscsi_flags |= USCSI_WRITE; + } + req.uscsi_buflen = sp->size; + req.uscsi_bufaddr = sp->addr; + req.uscsi_timeout = sp->timeout; + req.uscsi_cdblen = sp->cdb_len; + req.uscsi_rqbuf = (caddr_t) sp->u_sense.cmd_sense; + req.uscsi_rqlen = sp->sense_len; + req.uscsi_cdb = (caddr_t) &sp->cdb; + + if (cureuid != 0) + seteuid(0); +again: + errno = 0; + ret = ioctl(usalp->fd, USCSICMD, &req); + + if (ret < 0 && geterrno() == EPERM) { /* XXX Hack until we have uid management */ + cureuid = geteuid(); + if (seteuid(0) >= 0) + goto again; + } + if (cureuid != 0) + seteuid(cureuid); + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, "ret: %d errno: %d (%s)\n", ret, errno, errmsgstr(errno)); + fprintf((FILE *)usalp->errfile, "uscsi_flags: 0x%x\n", req.uscsi_flags); + fprintf((FILE *)usalp->errfile, "uscsi_status: 0x%x\n", req.uscsi_status); + fprintf((FILE *)usalp->errfile, "uscsi_timeout: %d\n", req.uscsi_timeout); + fprintf((FILE *)usalp->errfile, "uscsi_bufaddr: 0x%lx\n", (long)req.uscsi_bufaddr); + /* + * Cast auf int OK solange sp->size + * auch ein int bleibt. + */ + fprintf((FILE *)usalp->errfile, "uscsi_buflen: %d\n", (int)req.uscsi_buflen); + fprintf((FILE *)usalp->errfile, "uscsi_resid: %d\n", (int)req.uscsi_resid); + fprintf((FILE *)usalp->errfile, "uscsi_rqlen: %d\n", req.uscsi_rqlen); + fprintf((FILE *)usalp->errfile, "uscsi_rqstatus: 0x%x\n", req.uscsi_rqstatus); + fprintf((FILE *)usalp->errfile, "uscsi_rqresid: %d\n", req.uscsi_rqresid); + fprintf((FILE *)usalp->errfile, "uscsi_rqbuf ptr: 0x%lx\n", (long)req.uscsi_rqbuf); + fprintf((FILE *)usalp->errfile, "uscsi_rqbuf: "); + if (req.uscsi_rqbuf != NULL && req.uscsi_rqlen > req.uscsi_rqresid) { + int i; + int len = req.uscsi_rqlen - req.uscsi_rqresid; + + for (i = 0; i < len; i++) { + fprintf((FILE *)usalp->errfile, "0x%02X ", ((char *)req.uscsi_rqbuf)[i]); + } + fprintf((FILE *)usalp->errfile, "\n"); + } else { + fprintf((FILE *)usalp->errfile, "<data not available>\n"); + } + } + if (ret < 0) { + sp->ux_errno = geterrno(); + /* + * Check if SCSI command cound not be send at all. + */ + if (sp->ux_errno == ENOTTY && usalo_uisatapi(usalp) == TRUE) { + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "ENOTTY atapi: %d\n", usalo_uisatapi(usalp)); + } + sp->error = SCG_FATAL; + return (0); + } + if (errno == ENXIO) { + sp->error = SCG_FATAL; + return (0); + } + if (errno == ENOTTY || errno == EINVAL || errno == EACCES) { + return (-1); + } + } else { + sp->ux_errno = 0; + } + ret = 0; + sp->sense_count = req.uscsi_rqlen - req.uscsi_rqresid; + sp->resid = req.uscsi_resid; + sp->u_scb.cmd_scb[0] = req.uscsi_status; + + if ((req.uscsi_status & STATUS_MASK) == STATUS_GOOD) { + sp->error = SCG_NO_ERROR; + return (0); + } + if (req.uscsi_rqstatus == 0 && + ((req.uscsi_status & STATUS_MASK) == STATUS_CHECK)) { + sp->error = SCG_NO_ERROR; + return (0); + } + if (req.uscsi_status & (STATUS_TERMINATED | + STATUS_RESERVATION_CONFLICT)) { + sp->error = SCG_FATAL; + } + if (req.uscsi_status != 0) { + /* + * This is most likely wrong. There seems to be no way + * to produce SCG_RETRYABLE with USCSI. + */ + sp->error = SCG_RETRYABLE; + } + + return (ret); +} +#endif /* USE_USCSI */ diff --git a/libusal/scsi-unixware.c b/libusal/scsi-unixware.c new file mode 100644 index 0000000..4a149f1 --- /dev/null +++ b/libusal/scsi-unixware.c @@ -0,0 +1,922 @@ +/* + * 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-unixware.c 1.36 04/01/15 Copyright 1998 J. Schilling, Santa Cruz Operation */ +/* + * Interface for the SCO UnixWare SCSI implementation. + * + * 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. + * + * Copyright (c) 1998 J. Schilling, Santa Cruz Operation + */ +/* + * 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 +#undef SC_PARITY +#undef scb + +#include <sys/sysmacros.h> /* XXX Falsch, richtig -> sys/mkdev.h */ +#include <sys/scsi.h> +#include <sys/sdi_edt.h> +#include <sys/sdi.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-unixware.c-1.36"; /* The version for this transport*/ + +/* Max. number of usal scsibusses. The real limit would be */ +/* MAX_HBA * MAX_BUS (which would be 32 * 8 on UnixWare 2.1/7.x), */ +/* but given that we will hardly see such a beast, lets take 32 */ + +#define MAX_SCG 32 + + /* maximum defines for UnixWare 2.x/7.x from <sys/sdi_edt.h> */ + +#define MAX_TGT MAX_EXTCS /* Max # of target id's */ +#define MAX_LUN MAX_EXLUS /* Max # of lun's */ + +#define MAX_DMA (32*1024) +#ifdef __WHAT_TODO__ +#define MAX_DMA (16*1024) /* On UnixWare 2.1.x w/ AHA2940 HBA */ + /* the max DMA size is 16KB. */ +#endif + +#define MAXLINE 80 +#define MAXPATH 256 + +#define DEV_DIR "/tmp" +#define DEV_NAME "usal.s%1dt%1dl%1d" + +#define SCAN_HBA "%d:%d,%d,%d:%7s : %n" +#define SCAN_DEV "%d,%d,%d:%7s : %n" + +#define PRIM_HBA "/dev/hba/hba1" +#define SCSI_CFG "LC_ALL=C /etc/scsi/pdiconfig -l" + +#define SCAN_ALL "LIBSCG_SCAN_ALL" + +#define SDI_VALID 0x01 /* Entry may be used (non disk) */ +#define SDI_ATAPI 0x02 /* Connected via IDE HBA */ +#define SDI_INITIATOR 0x04 /* This is the initiator target ID */ + +typedef struct usal2sdi { + short open; + short flags; + short fd; + char hba; + char bus; + char tgt; + char lun; + + dev_t node; + dev_t major; + dev_t minor; +/*#define SCG_DEBUG*/ +#ifdef SCG_DEBUG + char type[20]; + char vend[40]; + char devn[32]; +#endif +} usal2sdi_t; + +static usal2sdi_t sdidevs [MAX_SCG][MAX_TGT][MAX_LUN]; +static BOOL sdiinit = FALSE; + +struct usal_local { + short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN]; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +static int unixware_init(SCSI *usalp); +static int do_usal_cmd(SCSI *usalp, struct usal_cmd *sp); +static int do_usal_sense(SCSI *usalp, struct usal_cmd *sp); +static FILE *xpopen(char *cmd, char *type); +static int xpclose(FILE *f); + +/* + * ------------------------------------------------------------------------- + * SCO UnixWare 2.1.x / UnixWare 7 provides a scsi pass-through mechanism, + * which can be used to access any configured scsi device. + * + * NOTE: The libusal UnixWare passthrough routines have changed with + * cdrecord-1.8 to enable the -scanbus, -load, -eject option + * regardless of the status of media and the addressing + * scheme is now the same as used on many other platforms like + * Solaris, Linux etc. + * + * =============================================================== + * RUN 'cdrecord -scanbus' TO SEE THE DEVICE ADDRESSES YOU CAN USE + * =============================================================== + */ + +/* + * 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, "SDI_SEND", "Generic SCSI", + "", "bus,target,lun", "1,2,0", TRUE, FALSE); + return (0); +} + +/* + * --------------------------------------------------------------- + * This routine is introduced to create all device nodes necessary + * to access any detected scsi device. It parses the output of + * /etc/scsi/pdiconfig -l and creates passthru device node for each + * found scsi device apart from the listed hba's. + * + */ + +static int +unixware_init(SCSI *usalp) +{ + FILE *cmd; + int hba = 0, bus = 0, usal = 0, tgt = 0, lun = 0; + int nusal = -1, lhba = -1, lbus = 0; + int atapi, fd, nopen = 0, pos = 0, len = 0; + int s, t, l; + int scan_disks; + char lines[MAXLINE]; + char class[MAXLINE]; + char ident[MAXLINE]; + char devnm[MAXPATH]; + char dname[MAXPATH]; + struct stat stbuf; + dev_t ptdev, major, minor, node; + char **evsave; +extern char **environ; + + /* Check for validity of primary hostbus adapter node */ + + if (stat(PRIM_HBA, &stbuf) < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Can not stat() primary hba (%s)", + PRIM_HBA); + return (-1); + } + + if (!S_ISCHR(stbuf.st_mode)) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Primary hba (%s) not a character device", + PRIM_HBA); + return (-1); + } + + major = getmajor(stbuf.st_rdev); + + /* + * Check whether we want to scan all devices + */ + if (getenv(SCAN_ALL) != NULL) { + scan_disks = 1; + } else { + scan_disks = 0; + } + + /* read pdiconfig output and get all attached scsi devices ! */ + + evsave = environ; + environ = 0; + if ((cmd = xpopen(SCSI_CFG, "r")) == NULL) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Error popen() for \"%s\"", + SCSI_CFG); + environ = evsave; + return (-1); + } + environ = evsave; + + + for (;;) { + if (fgets(lines, MAXLINE, cmd) == NULL) + break; + + memset(class, '\0', sizeof (class)); + memset(ident, '\0', sizeof (ident)); + + if (lines[0] == ' ') { + sscanf(lines, SCAN_DEV, &bus, &tgt, &lun, class, &pos); + hba = lhba; + } else { + sscanf(lines, SCAN_HBA, &hba, &bus, &tgt, &lun, class, &pos); + nusal++; + lhba = hba; + atapi = 0; + } + + /* We can't sscanf() the ident string of the device */ + /* as it may contain characters sscanf() will */ + /* recognize as a delimiter. So do a strcpy() instead ! */ + + len = strlen(lines) - pos - 1; /* don't copy the '\n' */ + + strncpy(ident, &lines[pos], len); + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "SDI -> %d:%d,%d,%d: %-7s : %s\n", + hba, bus, tgt, lun, class, ident); + } + if (bus != lbus) { + nusal++; + lbus = bus; + } + + usal = nusal; + + /* check whether we have a HBA or a SCSI device, don't */ + /* let HBA's be valid device for cdrecord, but mark */ + /* them as a controller (initiator = 1). */ + + /* Don't detect disks, opening a mounted disk can hang */ + /* the disk subsystem !!! So unless we set an */ + /* environment variable LIBSCG_SCAN_ALL, we will ignore */ + /* disks */ + + if (strstr(class, "HBA") == NULL) { + if (strstr(class, "DISK") != NULL) { + if (scan_disks) + sdidevs[usal][tgt][lun].flags |= SDI_VALID; + else + sdidevs[usal][tgt][lun].flags &= ~SDI_VALID; + } else { + sdidevs[usal][tgt][lun].flags |= SDI_VALID; + } + } else { + sdidevs[usal][tgt][lun].flags |= SDI_INITIATOR; + } + + + /* There is no real flag that shows a HBA as an ATAPI */ + /* controller, so as we know the driver is called 'ide' */ + /* we can check the ident string for the occurence of it*/ + + if (strstr(ident, "(ide,") != NULL) { + atapi = 1; + } + + /* + * Fill the sdidevs array with all we know now. + * Do not overwrite fields that may contain old state like + * sdidevs[usal][tgt][lun].open + */ + + if (atapi) + sdidevs[usal][tgt][lun].flags |= SDI_ATAPI; + else + sdidevs[usal][tgt][lun].flags &= ~SDI_ATAPI; + + sdidevs[usal][tgt][lun].hba = hba; + sdidevs[usal][tgt][lun].bus = bus; + sdidevs[usal][tgt][lun].tgt = tgt; + sdidevs[usal][tgt][lun].lun = lun; + +#ifdef SCG_DEBUG + strcpy(sdidevs[usal][tgt][lun].type, class); + strcpy(sdidevs[usal][tgt][lun].vend, ident); + + snprintf(sdidevs[usal][tgt][lun].devn, + sizeof (sdidevs[usal][tgt][lun].devn), + DEV_NAME, usal, tgt, lun); +#endif + snprintf(devnm, sizeof (devnm), + DEV_NAME, usal, tgt, lun); + + minor = SDI_MINOR(hba, tgt, lun, bus); + node = makedevice(major, minor); + + sdidevs[usal][tgt][lun].major = major; + sdidevs[usal][tgt][lun].minor = minor; + sdidevs[usal][tgt][lun].node = node; + + if (usalp->debug > 0) { + + fprintf((FILE *)usalp->errfile, + "h = %d; b = %d, s = %d, t = %d, l = %d, a = %d, ma = %d, mi = %2d, dev = '%s', id = '%s'\n", + hba, bus, usal, tgt, lun, + (sdidevs[usal][tgt][lun].flags & SDI_ATAPI) != 0, + sdidevs[usal][tgt][lun].major, + sdidevs[usal][tgt][lun].minor, + devnm, + ident); + } + + + } + + if (xpclose(cmd) == -1) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Error pclose() for \"%s\"", + SCSI_CFG); + return (-1); + } + + + /* create all temporary device nodes */ + + for (s = 0; s < MAX_SCG; s++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + + if ((sdidevs[s][t][l].flags & SDI_VALID) == 0) { + if (sdidevs[s][t][l].fd >= 0) { + close(sdidevs[s][t][l].fd); + } + sdidevs[s][t][l].fd = -1; + sdidevs[s][t][l].open = 0; + continue; + } + + /* Make pass-through interface device node */ + + snprintf(devnm, + sizeof (devnm), + DEV_NAME, s, t, l); + + snprintf(dname, sizeof (dname), + "%s/%s", DEV_DIR, devnm); + + ptdev = sdidevs[s][t][l].node; + + if (mknod(dname, S_IFCHR | 0700, ptdev) < 0) { + if (errno == EEXIST) { + unlink(dname); + + if (mknod(dname, S_IFCHR | 0700, ptdev) < 0) { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "mknod() error for \"%s\"", dname); + return (-1); + } + } else { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "mknod() error for \"%s\"", dname); + return (-1); + } + } + + /* Open pass-through device node */ + + if ((fd = open(dname, O_RDONLY)) < 0) { + if (errno == EBUSY && sdidevs[s][t][l].open > 0) { + /* + * Device has already been opened, just + * return the saved file desc. + */ + fd = sdidevs[s][t][l].fd; + } else { + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "can not open pass-through %s", dname); + return (-1); + } + } + + /* + * If for whatever reason we may open a pass through + * device more than once, this will waste fs's as we + * do not check for sdidevs[s][t][l].fd == -1. + */ + sdidevs[s][t][l].fd = fd; + sdidevs[s][t][l].open++; + nopen++; + usallocal(usalp)->usalfiles[s][t][l] = (short) fd; + + if (usalp->debug > 0) { + + fprintf((FILE *)usalp->errfile, + "s = %d, t = %d, l = %d, dev = %s, fd = %d\n", + s, t, l, + devnm, + sdidevs[s][t][l].fd); + } + + } + } + } + + return (nopen); +} + + +static int +usalo_open(SCSI *usalp, char *device) +{ + int busno = usal_scsibus(usalp); + int tgt = usal_target(usalp); + int tlun = usal_lun(usalp); + int b, t, l; + + 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 (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } + + if (!sdiinit) { + sdiinit = TRUE; + memset(sdidevs, 0, sizeof (sdidevs)); /* init tmp_structure */ + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + + sdidevs[b][t][l].flags = 0; + sdidevs[b][t][l].fd = -1; + sdidevs[b][t][l].open = 0; + } + } + } + } + + if (*device != '\0') { /* we don't allow old dev usage */ + errno = EINVAL; + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Open by 'devname' no longer supported on this OS"); + return (-1); + } else { /* this is the new stuff */ + /* it will do the initialisation */ + /* and return the number of */ + /* detected devices to be used */ + /* with the new addressing */ + /* scheme. */ + + return (unixware_init(usalp)); + } + +} + + +static int +usalo_close(SCSI *usalp) +{ + register int f; + register int b; + register int t; + register int l; + + if (usalp->local == NULL) + return (-1); + + for (b = 0; b < MAX_SCG; b++) { + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) { + + f = usallocal(usalp)->usalfiles[b][t][l]; + if (f >= 0) { + if (sdidevs[b][t][l].open > 0) + sdidevs[b][t][l].open--; + if (sdidevs[b][t][l].open <= 0) { + if (sdidevs[b][t][l].fd >= 0) + close(sdidevs[b][t][l].fd); + sdidevs[b][t][l].fd = -1; + sdidevs[b][t][l].flags &= ~SDI_VALID; + } + } + usallocal(usalp)->usalfiles[b][t][l] = (short)-1; + } + } + } + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + return (MAX_DMA); +} + + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = (void *) valloc((size_t)(amt)); + + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + 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); + + if (usalp->local == NULL) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if (usallocal(usalp)->usalfiles[busno][t][l] >= 0) + return (TRUE); + } + return (FALSE); +} + +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); + + if (usalp->local == NULL) + return (-1); + + return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]); +} + +static int +usalo_initiator_id(SCSI *usalp) +{ + register int t; + register int l; + register int busno; + + busno = usal_scsibus(usalp); + + if (busno < 0 || busno >= MAX_SCG) + return (FALSE); + + for (t = 0; t < MAX_TGT; t++) { + for (l = 0; l < MAX_LUN; l++) + if ((sdidevs[busno][t][l].flags & SDI_INITIATOR) != 0) { + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_initiator_id: id = %d\n", t); + } + return (t); + } + } + + return (-1); +} + +static int +usalo_isatapi(SCSI *usalp) +{ + /* if the new address method is used we know if this is ATAPI */ + + return ((sdidevs[usal_scsibus(usalp)][usal_target(usalp)][usal_lun(usalp)].flags & SDI_ATAPI) != 0); +} + +static int +usalo_reset(SCSI *usalp, int what) +{ + int f = usalp->fd; + + errno = EINVAL; + +#if defined(SDI_TRESET) || defined(SDI_BRESET) + if (what == SCG_RESET_NOP) { + errno = 0; + return (0); + } + +#ifdef SDI_TRESET + if (what == SCG_RESET_TGT) { + errno = 0; + if (ioctl(f, SDI_TRESET, 0) >= 0) + return (0); + } +#endif + +#ifdef SDI_BRESET + if (what == SCG_RESET_BUS) { + errno = 0; + if (ioctl(f, SDI_BRESET, 0) >= 0) + return (0); + } +#endif + +#endif /* defined(SDI_TRESET) || defined(SDI_BRESET) */ + + return (-1); +} + +static int +do_usal_cmd(SCSI *usalp, struct usal_cmd *sp) +{ + int ret; + int i; + struct sb scsi_cmd; + struct scb *scbp; + + memset(&scsi_cmd, 0, sizeof (scsi_cmd)); + + scsi_cmd.sb_type = ISCB_TYPE; + scbp = &scsi_cmd.SCB; + + scbp->sc_cmdpt = (caddr_t) sp->cdb.cmd_cdb; + scbp->sc_cmdsz = sp->cdb_len; + + scbp->sc_datapt = sp->addr; + scbp->sc_datasz = sp->size; + + if (!(sp->flags & SCG_RECV_DATA) && (sp->size > 0)) + scbp->sc_mode = SCB_WRITE; + else + scbp->sc_mode = SCB_READ; + + scbp->sc_time = sp->timeout; + + sp->error = SCG_NO_ERROR; + errno = 0; + for (;;) { + if ((ret = ioctl(usalp->fd, SDI_SEND, &scsi_cmd)) < 0) { + if (errno == EAGAIN) { + sleep(1); + errno = 0; + continue; + } + sp->ux_errno = errno; + if (errno == 0) + sp->ux_errno = EIO; + sp->error = SCG_RETRYABLE; + +#ifdef __needed__ + if (errno == ENOTTY || errno == EINVAL || + errno == EACCES) { + return (-1); + } +#endif + return (ret); + } + break; + } + sp->ux_errno = errno; + sp->resid = scbp->sc_resid; + memset(&sp->u_scb.Scb, 0, sizeof (sp->u_scb.Scb)); + sp->u_scb.cmd_scb[0] = scbp->sc_status; + + if (sp->u_scb.cmd_scb[0] & 0x02) { + if (sp->ux_errno == 0) + sp->ux_errno = EIO; + } + + switch (scbp->sc_comp_code) { + + case SDI_ASW : /* Job completed normally */ + case SDI_LINKF0 : /* Linked command done without flag */ + case SDI_LINKF1 : /* Linked command done with flag */ + + sp->error = SCG_NO_ERROR; + break; + + case SDI_CKSTAT : /* Check the status byte */ + + sp->error = SCG_NO_ERROR; + break; + + case SDI_NOALLOC : /* This block is not allocated */ + case SDI_NOTEQ : /* Addressed device not present */ + case SDI_OOS : /* Device is out of service */ + case SDI_NOSELE : /* The SCSI bus select failed */ + case SDI_SBRESC : /* SCSI bus reservation conflict */ + + sp->error = SCG_FATAL; + if (sp->ux_errno == 0) + sp->ux_errno = EIO; + break; + + case SDI_QFLUSH : /* Job was flushed */ + case SDI_ABORT : /* Command was aborted */ + case SDI_RESET : /* Reset was detected on the bus */ + case SDI_CRESET : /* Reset was caused by this unit */ + case SDI_V2PERR : /* vtop failed */ + case SDI_HAERR : /* Host adapter error */ + case SDI_MEMERR : /* Memory fault */ + case SDI_SBUSER : /* SCSI bus error */ + case SDI_SCBERR : /* SCB error */ + case SDI_MISMAT : /* parameter mismatch */ + + case SDI_PROGRES : /* Job in progress */ + case SDI_UNUSED : /* Job not in use */ + + case SDI_ONEIC : /* More than one immediate request */ + case SDI_SFBERR : /* SFB error */ + case SDI_TCERR : /* Target protocol error detected */ + default: + sp->error = SCG_RETRYABLE; + if (sp->ux_errno == 0) + sp->ux_errno = EIO; + break; + + case SDI_TIME : /* Job timed out */ + case SDI_TIME_NOABORT : /* Job timed out, but could not be aborted */ + + sp->error = SCG_TIMEOUT; + if (sp->ux_errno == 0) + sp->ux_errno = EIO; + break; + } + return (0); +} + + +static int +do_usal_sense(SCSI *usalp, struct usal_cmd *sp) +{ + int ret; + struct usal_cmd s_cmd; + + memset((caddr_t)&s_cmd, 0, sizeof (s_cmd)); + + s_cmd.addr = (caddr_t) sp->u_sense.cmd_sense; + s_cmd.size = sp->sense_len; + s_cmd.flags = SCG_RECV_DATA|SCG_DISRE_ENA; + s_cmd.cdb_len = SC_G0_CDBLEN; + s_cmd.sense_len = CCS_SENSE_LEN; + + s_cmd.cdb.g0_cdb.cmd = SC_REQUEST_SENSE; + s_cmd.cdb.g0_cdb.lun = sp->cdb.g0_cdb.lun; + s_cmd.cdb.g0_cdb.count = sp->sense_len; + + ret = do_usal_cmd(usalp, &s_cmd); + + if (ret < 0) + return (ret); + + sp->sense_count = sp->sense_len - s_cmd.resid; + return (ret); +} + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + int ret; + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + + ret = do_usal_cmd(usalp, sp); + if (ret < 0) + return (ret); + + if (sp->u_scb.cmd_scb[0] & S_CKCON) + ret = do_usal_sense(usalp, sp); + + return (ret); +} + +#define sense u_sense.Sense +#undef SC_PARITY +#define SC_PARITY 0x09 +#define scb u_scb.Scb + +/*--------------------------------------------------------------------------*/ +#include <unixstd.h> +#include <waitdefs.h> +/* + * Simplified version of popen() + * This version of popen() is not usable more than once at a time. + * Needed because /etc/scsi/pdiconfig will not work if euid != uid + */ +static pid_t po_pid; + +static FILE * +xpopen(char *cmd, char *type) +{ + FILE *ret; + FILE *pp[2]; + + if (po_pid != 0) + return ((FILE *)NULL); + + if (*type != 'r') + return ((FILE *)NULL); + + if (fpipe(pp) == 0) + return ((FILE *)NULL); + + + if ((po_pid = fork()) == 0) { + setuid(0); + + fclose(pp[0]); + (void) rols_fexecl("/bin/sh", stdin, pp[1], stderr, + "sh", "-c", cmd, (char *)0); + _exit(1); + } + fclose(pp[1]); + + if (po_pid == (pid_t)-1) { + fclose(pp[0]); + return ((FILE *)NULL); + } + return (pp[0]); +} + +static int +xpclose(FILE *f) +{ + int ret = 0; + + if (po_pid == 0) + return (-1); + + fclose(f); + + if (waitpid(po_pid, &ret, 0) < 0) + ret = -1; + + po_pid = 0; + return (ret); +} diff --git a/libusal/scsi-vms.c b/libusal/scsi-vms.c new file mode 100644 index 0000000..ef29d76 --- /dev/null +++ b/libusal/scsi-vms.c @@ -0,0 +1,540 @@ +/* + * 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-vms.c 1.33 04/01/15 Copyright 1997 J. Schilling */ +/* + * Interface for the VMS generic SCSI implementation. + * + * The idea for an elegant mapping to VMS device dontroller names + * is from Chip Dancy Chip.Dancy@hp.com. This allows up to + * 26 IDE controllers (DQ[A-Z][0-1]). + * + * This is a hack, that tries to emulate the functionality + * of the usal driver. + * + * 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. + * + * Copyright (c) 1997 J. Schilling + */ +/* + * 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. + */ + +#include <iodef.h> +#include <ssdef.h> +#include <descrip.h> +#include <starlet.h> +#include <string.h> +#include <LIB$ROUTINES.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-vms.c-1.33"; /* The version for this transport*/ + +#define VMS_MAX_DK 4 /* DK[A-D] VMS device controllers */ +#define VMS_MAX_GK 4 /* GK[A-D] VMS device controllers */ +#define VMS_MAX_DQ 26 /* DQ[A-Z] VMS device controllers */ + +#define VMS_DKRANGE_MAX VMS_MAX_DK +#define VMS_GKRANGE_MAX (VMS_DKRANGE_MAX + VMS_MAX_GK) +#define VMS_DQRANGE_MAX (VMS_GKRANGE_MAX + VMS_MAX_DQ) + +#define MAX_SCG VMS_DQRANGE_MAX /* Max # of SCSI controllers */ +#define MAX_TGT 16 +#define MAX_LUN 8 + +#define MAX_DMA_VMS (63*1024) /* Check if this is not too big */ +#define MAX_PHSTMO_VMS 300 +#define MAX_DSCTMO_VMS ((64*1024)-1) /* max value for OpenVMS/AXP 7.1 ehh*/ + +/* + * Define a mapping from the scsi busno to the three character + * VMS device controller. + * The valid busno values are broken into three ranges, one for each of + * the three supported devices: dk, gk, and dq. + * The vmschar[] and vmschar1[] arrays are subscripted by an offset + * corresponding to each of the three ranges [0,1,2] to provide the + * two characters of the VMS device. + * The offset of the busno value within its range is used to define the + * third character, using the vmschar2[] array. + */ +static char vmschar[] = {'d', 'g', 'd'}; +static char vmschar1[] = {'k', 'k', 'q'}; +static char vmschar2[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z'}; + + +static int do_usal_cmd(SCSI *usalp, struct usal_cmd *sp); +static int do_usal_sense(SCSI *usalp, struct usal_cmd *sp); + +#define DEVICE_NAMELEN 8 + +struct SCSI$DESC { + Uint SCSI$L_OPCODE; /* SCSI Operation Code */ + Uint SCSI$L_FLAGS; /* SCSI Flags Bit Map */ + char *SCSI$A_CMD_ADDR; /* ->SCSI command buffer */ + Uint SCSI$L_CMD_LEN; /* SCSI command length, bytes */ + char *SCSI$A_DATA_ADDR; /* ->SCSI data buffer */ + Uint SCSI$L_DATA_LEN; /* SCSI data length, bytes */ + Uint SCSI$L_PAD_LEN; /* SCSI pad length, bytes */ + Uint SCSI$L_PH_CH_TMOUT; /* SCSI phase change timeout */ + Uint SCSI$L_DISCON_TMOUT; /* SCSI disconnect timeout */ + Uint SCSI$L_RES_1; /* Reserved */ + Uint SCSI$L_RES_2; /* Reserved */ + Uint SCSI$L_RES_3; /* Reserved */ + Uint SCSI$L_RES_4; /* Reserved */ + Uint SCSI$L_RES_5; /* Reserved */ + Uint SCSI$L_RES_6; /* Reserved */ +}; + +#ifdef __ALPHA +#pragma member_alignment save +#pragma nomember_alignment +#endif + +struct SCSI$IOSB { + Ushort SCSI$W_VMS_STAT; /* VMS status code */ + Ulong SCSI$L_IOSB_TFR_CNT; /* Actual #bytes transferred */ + char SCSI$B_IOSB_FILL_1; + Uchar SCSI$B_IOSB_STS; /* SCSI device status */ +}; + +#ifdef __ALPHA +#pragma member_alignment restore +#endif + +#define SCSI$K_GOOD_STATUS 0 +#define SCSI$K_CHECK_CONDITION 0x2 +#define SCSI$K_CONDITION_MET 0x4 +#define SCSI$K_BUSY 0x8 +#define SCSI$K_INTERMEDIATE 0x10 +#define SCSI$K_INTERMEDIATE_C_MET 0x14 +#define SCSI$K_RESERVATION_CONFLICT 0x18 +#define SCSI$K_COMMAND_TERMINATED 0x22 +#define SCSI$K_QUEUE_FULL 0x28 + + +#define SCSI$K_WRITE 0X0 /* direction of transfer=write */ +#define SCSI$K_READ 0X1 /* direction of transfer=read */ +#define SCSI$K_FL_ENAB_DIS 0X2 /* enable disconnects */ +#define SCSI$K_FL_ENAB_SYNC 0X4 /* enable sync */ +#define GK_EFN 0 /* Event flag number */ + +static char gk_device[8]; /* XXX JS hoffentlich gibt es keinen Ueberlauf */ +static Ushort gk_chan; +static Ushort transfer_length; +static int i; +static int status; +static $DESCRIPTOR(gk_device_desc, gk_device); +static struct SCSI$IOSB gk_iosb; +static struct SCSI$DESC gk_desc; +static FILE *fp; + + +struct usal_local { + Ushort gk_chan; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +/* + * 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, "IO$_DIAGNOSE", "Generic SCSI", + "", "bus,target,lun", "1,2,0", FALSE, 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); + char devname[DEVICE_NAMELEN]; + char buschar; + char buschar1; + char buschar2; + int range; + int range_offset; + + 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 (busno < 0 || tgt < 0 || tlun < 0) { + /* + * There is no real reason why we cannot scan on VMS, + * but for now it is not possible. + */ + if (usalp->errstr) + snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, + "Unable to scan on VMS"); + return (0); + } + + if (usalp->local == NULL) { + usalp->local = malloc(sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + } + + if (busno < VMS_DKRANGE_MAX) { /* in the dk range? */ + range = 0; + range_offset = busno; + } else if (busno < VMS_GKRANGE_MAX) { /* in the gk range? */ + range = 1; + range_offset = busno - VMS_DKRANGE_MAX; + } else if (busno < VMS_DQRANGE_MAX) { /* in the dq range? */ + range = 2; + range_offset = busno - VMS_GKRANGE_MAX; + } + buschar = vmschar[range]; /* get first device char*/ + buschar1 = vmschar1[range]; /* get 2nd device char*/ + buschar2 = vmschar2[range_offset]; /* get controller char*/ + + snprintf(devname, sizeof (devname), "%c%c%c%d0%d:", + buschar, buschar1, buschar2, + tgt, tlun); + strcpy(gk_device, devname); + status = sys$assign(&gk_device_desc, &gk_chan, 0, 0); + if (!(status & 1)) { + fprintf((FILE *)usalp->errfile, + "Unable to access scsi-device \"%s\"\n", &gk_device[0]); + return (-1); + } + if (usalp->debug > 0) { + fp = fopen("cdrecord_io.log", "w", "rfm=stmlf", "rat=cr"); + if (fp == NULL) { + perror("Failing opening i/o-logfile"); + exit(SS$_NORMAL); + } + } + return (status); +} + +static int +usalo_close(SCSI *usalp) +{ + /* + * XXX close gk_chan ??? + */ + /* + * sys$dassgn() + */ + + status = sys$dassgn(gk_chan); + + return (status); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + return (MAX_DMA_VMS); +} + +static BOOL +usalo_havebus(SCSI *usalp, int busno) +{ + if (gk_chan == 0) + return (FALSE); + return (TRUE); +} + +static int +usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun) +{ + if (gk_chan == 0) + return (-1); + return (gk_chan); +} + +static int +usalo_initiator_id(SCSI *usalp) +{ + return (-1); +} + +static int +usalo_isatapi(SCSI *usalp) +{ + int busno = usal_scsibus(usalp); + + if (busno >= 8) + return (TRUE); + + return (FALSE); +} + +static int +usalo_reset(SCSI *usalp, int what) +{ + errno = EINVAL; + return (-1); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = malloc((size_t)(amt)); /* XXX JS XXX valloc() ??? */ + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + usalp->bufbase = NULL; +} + +static int +do_usal_cmd(SCSI *usalp, struct usal_cmd *sp) +{ + char *cmdadr; + int notcmdretry; + int len; + Uchar scsi_sts; + int severity; + + /* XXX JS XXX This cannot be OK */ + notcmdretry = (sp->flags & SCG_CMD_RETRY)^SCG_CMD_RETRY; + /* error corrected ehh */ +/* + * XXX JS Wenn das notcmdretry Flag bei VMS auch 0x08 ist und Du darauf hoffst, + * XXX Dasz ich den Wert nie aendere, dann ist das richtig. + * XXX Siehe unten: Das gleiche gilt fuer SCG_RECV_DATA und SCG_DISRE_ENA !!! + */ + + cmdadr = (char *)sp->cdb.cmd_cdb; + /* XXX JS XXX This cannot be OK */ + gk_desc.SCSI$L_FLAGS = ((sp->flags & SCG_RECV_DATA) | + (sp->flags & SCG_DISRE_ENA)| + notcmdretry); + /* XXX siehe oben, das ist ein bitweises oder!!! */ + gk_desc.SCSI$A_DATA_ADDR = sp->addr; + gk_desc.SCSI$L_DATA_LEN = sp->size; + gk_desc.SCSI$A_CMD_ADDR = cmdadr; + gk_desc.SCSI$L_CMD_LEN = sp->cdb_len; + gk_desc.SCSI$L_PH_CH_TMOUT = sp->timeout; + gk_desc.SCSI$L_DISCON_TMOUT = sp->timeout; + if (gk_desc.SCSI$L_PH_CH_TMOUT > MAX_PHSTMO_VMS) + gk_desc.SCSI$L_PH_CH_TMOUT = MAX_PHSTMO_VMS; + if (gk_desc.SCSI$L_DISCON_TMOUT > MAX_DSCTMO_VMS) + gk_desc.SCSI$L_DISCON_TMOUT = MAX_DSCTMO_VMS; + gk_desc.SCSI$L_OPCODE = 1; /* SCSI Operation Code */ + gk_desc.SCSI$L_PAD_LEN = 0; /* SCSI pad length, bytes */ + gk_desc.SCSI$L_RES_1 = 0; /* Reserved */ + gk_desc.SCSI$L_RES_2 = 0; /* Reserved */ + gk_desc.SCSI$L_RES_3 = 0; /* Reserved */ + gk_desc.SCSI$L_RES_4 = 0; /* Reserved */ + gk_desc.SCSI$L_RES_5 = 0; /* Reserved */ + gk_desc.SCSI$L_RES_6 = 0; /* Reserved */ + if (usalp->debug > 0) { + fprintf(fp, "***********************************************************\n"); + fprintf(fp, "SCSI VMS-I/O parameters\n"); + fprintf(fp, "OPCODE: %d", gk_desc.SCSI$L_OPCODE); + fprintf(fp, " FLAGS: %d\n", gk_desc.SCSI$L_FLAGS); + fprintf(fp, "CMD:"); + for (i = 0; i < gk_desc.SCSI$L_CMD_LEN; i++) { + fprintf(fp, "%x ", sp->cdb.cmd_cdb[i]); + } + fprintf(fp, "\n"); + fprintf(fp, "DATA_LEN: %d\n", gk_desc.SCSI$L_DATA_LEN); + fprintf(fp, "PH_CH_TMOUT: %d", gk_desc.SCSI$L_PH_CH_TMOUT); + fprintf(fp, " DISCON_TMOUT: %d\n", gk_desc.SCSI$L_DISCON_TMOUT); + } + status = sys$qiow(GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, + &gk_desc, sizeof (gk_desc), 0, 0, 0, 0); + + + if (usalp->debug > 0) { + fprintf(fp, "qiow-status: %i\n", status); + fprintf(fp, "VMS status code %i\n", gk_iosb.SCSI$W_VMS_STAT); + fprintf(fp, "Actual #bytes transferred %i\n", gk_iosb.SCSI$L_IOSB_TFR_CNT); + fprintf(fp, "SCSI device status %i\n", gk_iosb.SCSI$B_IOSB_STS); + if (gk_iosb.SCSI$L_IOSB_TFR_CNT != gk_desc.SCSI$L_DATA_LEN) { + fprintf(fp, "#bytes transferred != DATA_LEN\n"); + } + } + + if (!(status & 1)) { /* Fehlerindikation fuer sys$qiow() */ + sp->ux_errno = geterrno(); + /* schwerwiegender nicht SCSI bedingter Fehler => return (-1) */ + if (sp->ux_errno == ENOTTY || sp->ux_errno == ENXIO || + sp->ux_errno == EINVAL || sp->ux_errno == EACCES) { + return (-1); + } + if (sp->ux_errno == 0) + sp->ux_errno == EIO; + } else { + sp->ux_errno = 0; + } + + sp->resid = gk_desc.SCSI$L_DATA_LEN - gk_iosb.SCSI$L_IOSB_TFR_CNT; + + if (usalo_isatapi(usalp)) { + scsi_sts = ((gk_iosb.SCSI$B_IOSB_STS >> 4) & 0x7); + } else { + scsi_sts = gk_iosb.SCSI$B_IOSB_STS; + } + + if (gk_iosb.SCSI$W_VMS_STAT == SS$_NORMAL && scsi_sts == 0) { + sp->error = SCG_NO_ERROR; + if (usalp->debug > 0) { + fprintf(fp, "scsi_sts == 0\n"); + fprintf(fp, "gk_iosb.SCSI$B_IOSB_STS == 0\n"); + fprintf(fp, "sp->error %i\n", sp->error); + fprintf(fp, "sp->resid %i\n", sp->resid); + } + return (0); + } + + severity = gk_iosb.SCSI$W_VMS_STAT & 0x7; + + if (severity == 4) { + sp->error = SCG_FATAL; + if (usalp->debug > 0) { + fprintf(fp, "scsi_sts & 2\n"); + fprintf(fp, "gk_iosb.SCSI$B_IOSB_STS & 2\n"); + fprintf(fp, "gk_iosb.SCSI$W_VMS_STAT & 0x7 == SS$_FATAL\n"); + fprintf(fp, "sp->error %i\n", sp->error); + } + return (0); + } + if (gk_iosb.SCSI$W_VMS_STAT == SS$_TIMEOUT) { + sp->error = SCG_TIMEOUT; + if (usalp->debug > 0) { + fprintf(fp, "scsi_sts & 2\n"); + fprintf(fp, "gk_iosb.SCSI$B_IOSB_STS & 2\n"); + fprintf(fp, "gk_iosb.SCSI$W_VMS_STAT == SS$_TIMEOUT\n"); + fprintf(fp, "sp->error %i\n", sp->error); + } + return (0); + } + sp->error = SCG_RETRYABLE; + sp->u_scb.cmd_scb[0] = scsi_sts; + if (usalp->debug > 0) { + fprintf(fp, "scsi_sts & 2\n"); + fprintf(fp, "gk_iosb.SCSI$B_IOSB_STS & 2\n"); + fprintf(fp, "gk_iosb.SCSI$W_VMS_STAT != 0\n"); + fprintf(fp, "sp->error %i\n", sp->error); + } + return (0); +} + +static int +do_usal_sense(SCSI *usalp, struct usal_cmd *sp) +{ + int ret; + struct usal_cmd s_cmd; + + fillbytes((caddr_t)&s_cmd, sizeof (s_cmd), '\0'); + s_cmd.addr = (char *)sp->u_sense.cmd_sense; + s_cmd.size = sp->sense_len; + s_cmd.flags = SCG_RECV_DATA|SCG_DISRE_ENA; + s_cmd.cdb_len = SC_G0_CDBLEN; + s_cmd.sense_len = CCS_SENSE_LEN; + s_cmd.cdb.g0_cdb.cmd = SC_REQUEST_SENSE; + s_cmd.cdb.g0_cdb.lun = sp->cdb.g0_cdb.lun; + s_cmd.cdb.g0_cdb.count = sp->sense_len; + ret = do_usal_cmd(usalp, &s_cmd); + + if (ret < 0) + return (ret); + if (s_cmd.u_scb.cmd_scb[0] & 02) { + /* XXX ??? Check condition on request Sense ??? */ + } + sp->sense_count = sp->sense_len - s_cmd.resid; + return (ret); +} + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + int ret; + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (0); + } + ret = do_usal_cmd(usalp, sp); + if (ret < 0) + return (ret); + if (sp->u_scb.cmd_scb[0] & 02) + ret = do_usal_sense(usalp, sp); + return (ret); +} diff --git a/libusal/scsi-wnt.c b/libusal/scsi-wnt.c new file mode 100644 index 0000000..ddce64b --- /dev/null +++ b/libusal/scsi-wnt.c @@ -0,0 +1,1848 @@ +/* + * 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-wnt.c 1.45 04/07/19 Copyright 1998-2004 J. Schilling, A.L. Faber, J.A. Key */ +/* + * Interface for the Win32 ASPI library. + * You need wnaspi32.dll and aspi32.sys + * Both can be installed from ASPI_ME + * + * 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. + * + * Copyright (c) 1998-2004 J. Schilling + * Copyright (c) 1999 A.L. Faber for the first implementation + * of this interface. + * TODO: + * - DMA resid handling + * - better handling of maxDMA + * - SCSI reset support + */ +/* + * 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. + */ + + +/* + * Include for Win32 ASPI AspiRouter + * + * NOTE: aspi-win32.h includes Windows.h and Windows.h includes + * Base.h which has a second typedef for BOOL. + * We define BOOL to make all local code use BOOL + * from Windows.h and use the hidden __SBOOL for + * our global interfaces. + */ +#define BOOL WBOOL /* This is the Win BOOL */ +#define format __format +#include <usal/aspi-win32.h> +#include <usal/spti-wnt.h> +#undef format + +#ifdef __CYGWIN32__ /* Use dlopen() */ +#include <dlfcn.h> +#endif + +/* + * 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-wnt.c-1.45"; /* The version for this transport*/ +static char _usal_itrans_version[] = "SPTI-scsi-wnt.c-1.45"; /* The version for SPTI */ + +/* + * Local defines and constants + */ +/*#define DEBUG_WNTASPI*/ + +#define MAX_SCG 16 /* Max # of SCSI controllers */ +#define MAX_TGT 16 /* Max # of SCSI Targets */ +#define MAX_LUN 8 /* Max # of SCSI LUNs */ + +#ifdef DEBUG_WNTASPI +#endif + +struct usal_local { + int dummy; + char *filenames[MAX_SCG][MAX_TGT][MAX_LUN]; + char drive_wanted; +}; +#define usallocal(p) ((struct usal_local *)((p)->local)) + +/* + * Local variables + */ +static int busses; +static DWORD (*pfnGetASPI32SupportInfo)(void) = NULL; +static DWORD (*pfnSendASPI32Command)(LPSRB) = NULL; +static BOOL (*pfnGetASPI32Buffer)(PASPI32BUFF) = NULL; +static BOOL (*pfnFreeASPI32Buffer)(PASPI32BUFF) = NULL; +static BOOL (*pfnTranslateASPI32Address)(PDWORD, PDWORD) = NULL; + +static int DriverLoaded = 0; /* ASPI or SPTI */ +static HANDLE hAspiLib = NULL; /* Used for Loadlib */ + +#define MAX_DMA_WNT (63L*1024L) /* ASPI-Driver allows up to 64k ??? */ + +/* + * Local function prototypes + */ +static void exit_func(void); +#ifdef DEBUG_WNTASPI +static void DebugScsiSend(SCSI *usalp, SRB_ExecSCSICmd *s, int bDisplayBuffer); +#endif +static void copy_sensedata(SRB_ExecSCSICmd *cp, struct usal_cmd *sp); +static void set_error(SRB_ExecSCSICmd *cp, struct usal_cmd *sp); +static BOOL open_driver(SCSI *usalp); +static BOOL load_aspi(SCSI *usalp); +static BOOL close_driver(void); +static int ha_inquiry(SCSI *usalp, int id, SRB_HAInquiry *ip); +#ifdef __USED__ +static int resetSCSIBus(SCSI *usalp); +#endif +static int scsiabort(SCSI *usalp, SRB_ExecSCSICmd *sp); + + +/* SPTI Start ---------------------------------------------------------------*/ +/* + * From scsipt.c - Copyright (C) 1999 Jay A. Key + * Homepage: http://akrip.sourceforge.net/ + * Native NT support functions via the SCSI Pass Through interface instead + * of ASPI. Although based on information from the NT 4.0 DDK from + * Microsoft, the information has been sufficiently distilled to allow + * compilation w/o having the DDK installed. + * added to scsi-wnt.c by Richard Stemmer, rs@epost.de + * See http://www.ste-home.de/cdrtools-spti/ + */ + +#define PREFER_SPTI 1 /* Prefer SPTI if available, else try ASPI, force ASPI with dev=ASPI: */ +/* #define CREATE_NONSHARED 1 */ /* open CDROM-Device not SHARED if possible */ +/* #define _DEBUG_SCSIPT 1 */ +#ifdef _DEBUG_SCSIPT +FILE *usalp_errfile; /* File for SPTI-Debug-Messages */ +#endif + +#define SENSE_LEN_SPTI 32 /* Sense length for ASPI is only 14 */ +#define NUM_MAX_NTSCSI_DRIVES 26 /* a: ... z: */ +#define NUM_FLOPPY_DRIVES 2 +#define NUM_MAX_NTSCSI_HA NUM_MAX_NTSCSI_DRIVES + +#define NTSCSI_HA_INQUIRY_SIZE 36 + +#define SCSI_CMD_INQUIRY 0x12 + +typedef struct { + BYTE ha; /* SCSI Bus # */ + BYTE tgt; /* SCSI Target # */ + BYTE lun; /* SCSI Lun # */ + BYTE PortNumber; /* SCSI Card # (\\.\SCSI%d) */ + BYTE PathId; /* SCSI Bus/Channel # on card n */ + BYTE driveLetter; /* Win32 drive letter (e.g. c:) */ + BOOL bUsed; /* Win32 drive letter is used */ + HANDLE hDevice; /* Win32 handle for ioctl() */ + BYTE inqData[NTSCSI_HA_INQUIRY_SIZE]; +} DRIVE; + +typedef struct { + BYTE numAdapters; + DRIVE drive[NUM_MAX_NTSCSI_DRIVES]; +} SPTIGLOBAL; + +static int InitSCSIPT(SCSI *usalp); +static int DeinitSCSIPT(void); +static void GetDriveInformation(BYTE i, DRIVE *pDrive); +static BYTE SPTIGetNumAdapters(void); +static BYTE SPTIGetDeviceIndex(BYTE ha, BYTE tgt, BYTE lun); +static DWORD SPTIHandleHaInquiry(LPSRB_HAInquiry lpsrb); +static DWORD SPTIExecSCSICommand(LPSRB_ExecSCSICmd lpsrb, int sptTimeOutValue, BOOL bBeenHereBefore); +static HANDLE GetFileHandle(BYTE i, BOOL openshared); + +static BOOL bSCSIPTInit = FALSE; +static SPTIGLOBAL sptiglobal; +static BOOL UsingSPTI = FALSE; +static BOOL ForceAccess = FALSE; +static int sptihamax; +static USHORT sptihasortarr[NUM_MAX_NTSCSI_HA]; + +/* + * Initialization of SCSI Pass Through Interface code. Responsible for + * setting up the array of SCSI devices. This code will be a little + * different from the normal code -- it will query each drive letter from + * C: through Z: to see if it is a CD. When we identify a CD, we then + * send CDB with the INQUIRY command to it -- NT will automagically fill in + * the PathId, TargetId, and Lun for us. + */ +static int InitSCSIPT(SCSI *usalp) { + BYTE i; + BYTE j; + char buf[4]; + UINT uDriveType; + int retVal = 0; + USHORT hasortval; + char adapter_name[20]; + HANDLE fh; + ULONG returned; + BOOL status; + char InquiryBuffer[2048]; + PSCSI_ADAPTER_BUS_INFO ai; + BYTE bus; + int id_wanted=-1; + + if (bSCSIPTInit) + return (0); + + /* + * Detect all Busses on all SCSI-Adapters + * Fill up map array that allows us to later assign devices to + * bus numbers. + */ + sptihamax = 0; + i = 0; + do { + snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\SCSI%d:", i); + fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, 0, NULL); + if (fh != INVALID_HANDLE_VALUE) { + status = DeviceIoControl(fh, + IOCTL_SCSI_GET_INQUIRY_DATA, + NULL, + 0, + InquiryBuffer, + 2048, + &returned, + FALSE); + if (status) { + ai = (PSCSI_ADAPTER_BUS_INFO) InquiryBuffer; + for (bus = 0; bus < ai->NumberOfBusses; bus++) { + sptihasortarr[sptihamax] = ((i<<8) | bus); + sptihamax++; + } + } + CloseHandle(fh); + } + i++; + } while (fh != INVALID_HANDLE_VALUE); + + errno = 0; + memset(&sptiglobal, 0, sizeof (SPTIGLOBAL)); + for (i = 0; i < NUM_MAX_NTSCSI_DRIVES; i++) + sptiglobal.drive[i].hDevice = INVALID_HANDLE_VALUE; + + for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++) { + snprintf(buf, sizeof (buf), "%c:\\", (char)('A'+i)); + uDriveType = GetDriveType(buf); +#ifdef CDROM_ONLY + if (uDriveType == DRIVE_CDROM) { +#else + if (TRUE) { +#endif + GetDriveInformation(i, &sptiglobal.drive[i]); + + if (sptiglobal.drive[i].bUsed) { + retVal++; + hasortval = (sptiglobal.drive[i].PortNumber<<8) | sptiglobal.drive[i].PathId; + for (j = 0; j < sptihamax; j++) { + if (hasortval <= sptihasortarr[j]) + break; + } + if (j == sptihamax) { + sptihasortarr[j] = hasortval; + sptihamax++; + } else if (hasortval < sptihasortarr[j]) { + memmove(&sptihasortarr[j+1], &sptihasortarr[j], (sptihamax-j) * sizeof (USHORT)); + sptihasortarr[j] = hasortval; + sptihamax++; + } + + /* shortcut for device names, remember the hit */ + if(uDriveType==DRIVE_CDROM && usalp->local) { + /* printf("seen, %d at %d, %d, %d\n", sptiglobal.drive[i].driveLetter, sptiglobal.drive[i].ha, sptiglobal.drive[i].tgt, sptiglobal.drive[i].lun); */ + if(usallocal(usalp)->drive_wanted && *buf==toupper(usallocal(usalp)->drive_wanted)) + id_wanted=i; + /* don't keep the names, serial search in _natname is sufficient */ + } + } + } + } + /* looks like a workaround for diverging ASPI and SPTI hostadapter numbers, + most likely an attempt to keep the world of fake numbers + consistent; + EB */ + if (sptihamax > 0) { + for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++) + if (sptiglobal.drive[i].bUsed) + for (j = 0; j < sptihamax; j++) { + if (sptihasortarr[j] == ((sptiglobal.drive[i].PortNumber<<8) | sptiglobal.drive[i].PathId)) { + sptiglobal.drive[i].ha = j; + break; + } + } + } + sptiglobal.numAdapters = SPTIGetNumAdapters(); + + bSCSIPTInit = TRUE; + if(id_wanted>0) { + usal_scsibus(usalp)=sptiglobal.drive[id_wanted].ha; + usal_target(usalp) =sptiglobal.drive[id_wanted].tgt; + usal_lun(usalp) =sptiglobal.drive[id_wanted].lun; + + //#if 1 + #ifdef _DEBUG_SCSIPT + fprintf(stderr, "named SCSIPT drive type %d found as %c, choosing %d, %d, %d\n", + uDriveType, + 'A'+id_wanted, + usal_scsibus(usalp), + usal_target(usalp), + usal_lun(usalp)); + #endif + } + + if (retVal > 0) + UsingSPTI = TRUE; + + return (retVal); +} + + +static int +DeinitSCSIPT(void) +{ + BYTE i; + + if (!bSCSIPTInit) + return (0); + + for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++) { + if (sptiglobal.drive[i].bUsed) { + CloseHandle(sptiglobal.drive[i].hDevice); + } + } + + sptiglobal.numAdapters = SPTIGetNumAdapters(); + + memset(&sptiglobal, 0, sizeof (SPTIGLOBAL)); + bSCSIPTInit = FALSE; + return (-1); +} + + +/* + * Returns the number of "adapters" present. + */ +static BYTE +SPTIGetNumAdapters(void) +{ + BYTE buf[256]; + WORD i; + BYTE numAdapters = 0; + + memset(buf, 0, 256); + + /* + * PortNumber 0 should exist, so pre-mark it. This avoids problems + * when the primary IDE drives are on PortNumber 0, but can't be opened + * because of insufficient privelege (ie. non-admin). + */ + buf[0] = 1; + for (i = 0; i < NUM_MAX_NTSCSI_DRIVES; i++) { + if (sptiglobal.drive[i].bUsed) + buf[sptiglobal.drive[i].ha] = 1; + } + + for (i = 0; i <= 255; i++) + if (buf[i]) + numAdapters = (BYTE)(i + 1); + +/* numAdapters++; */ + + return (numAdapters); +} + +#include <ctype.h> +static BOOL +w2k_or_newer(void) +{ + OSVERSIONINFO osver; + + memset(&osver, 0, sizeof (osver)); + osver.dwOSVersionInfoSize = sizeof (osver); + GetVersionEx(&osver); + if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { + /* + * Win2000 is NT-5.0, Win-XP is NT-5.1 + */ + if (osver.dwMajorVersion > 4) + return (TRUE); + } + return (FALSE); +} + +static BOOL +w2kstyle_create(void) +{ + OSVERSIONINFO osver; + +/* return FALSE; */ + memset(&osver, 0, sizeof (osver)); + osver.dwOSVersionInfoSize = sizeof (osver); + GetVersionEx(&osver); + if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { + /* + * Win2000 is NT-5.0, Win-XP is NT-5.1 + */ + if (osver.dwMajorVersion > 4) + return (TRUE); + + if (osver.dwMajorVersion == 4) { /* NT-4.x */ + char *vers = osver.szCSDVersion; + + if (strlen(vers) == 0) + return (FALSE); + + /* + * Servicepack is installed, skip over non-digit part + */ + while (*vers != '\0' && !isdigit(*vers)) + vers++; + if (*vers == '\0') + return (FALSE); + + if (isdigit(vers[0]) && + (atoi(vers) >= 4 || isdigit(vers[1]))) /* Fom Service Pack 4 */ + return (TRUE); /* same as for W2K */ + } + } + return (FALSE); +} + + +/* + * Universal function to get a file handle to the CD device. Since + * NT 4.0 wants just the GENERIC_READ flag, and Win2K wants both + * GENERIC_READ and GENERIC_WRITE (why a read-only CD device needs + * GENERIC_WRITE access is beyond me...), the easist workaround is to just + * try them both. + */ +static HANDLE +GetFileHandle(BYTE i, BOOL openshared) +{ + char buf[12]; + HANDLE fh; + DWORD dwFlags = GENERIC_READ; + DWORD dwAccessMode = 0; + + dwAccessMode = FILE_SHARE_READ; + if (w2kstyle_create()) { /* if Win2K or greater, add GENERIC_WRITE */ + dwFlags |= GENERIC_WRITE; + dwAccessMode |= FILE_SHARE_WRITE; +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, "SPTI: GetFileHandle(): Setting for Win2K\n"); +#endif + } + snprintf(buf, sizeof (buf), "\\\\.\\%c:", (char)('A'+i)); +#ifdef CREATE_NONSHARED + if (openshared) { + fh = CreateFile(buf, dwFlags, dwAccessMode, NULL, + OPEN_EXISTING, 0, NULL); + } else { + fh = CreateFile(buf, dwFlags, 0, NULL, + OPEN_EXISTING, 0, NULL); + } + if (!openshared && fh == INVALID_HANDLE_VALUE && GetLastError() == ERROR_SHARING_VIOLATION) +#endif + fh = CreateFile(buf, dwFlags, dwAccessMode, NULL, + OPEN_EXISTING, 0, NULL); + if (fh == INVALID_HANDLE_VALUE) { + /* + * it went foobar somewhere, so try it with the GENERIC_WRITE + * bit flipped + */ + dwFlags ^= GENERIC_WRITE; + dwAccessMode ^= FILE_SHARE_WRITE; +#ifdef CREATE_NONSHARED + if (openshared) { + fh = CreateFile(buf, dwFlags, dwAccessMode, NULL, + OPEN_EXISTING, 0, NULL); + } else { + fh = CreateFile(buf, dwFlags, 0, NULL, + OPEN_EXISTING, 0, NULL); + } + if (!openshared && fh == INVALID_HANDLE_VALUE && GetLastError() == ERROR_SHARING_VIOLATION) +#endif + fh = CreateFile(buf, dwFlags, dwAccessMode, NULL, + OPEN_EXISTING, 0, NULL); + } +#ifdef _DEBUG_SCSIPT + if (fh == INVALID_HANDLE_VALUE) + fprintf(usalp_errfile, "SPTI: CreateFile() failed! -> %d\n", GetLastError()); + else + fprintf(usalp_errfile, "SPTI: CreateFile() returned %d\n", GetLastError()); +#endif + + return (fh); +} + + +/* + * fills in a pDrive structure with information from a SCSI_INQUIRY + * and obtains the ha:tgt:lun values via IOCTL_SCSI_GET_ADDRESS + */ +static void GetDriveInformation(BYTE i, DRIVE *pDrive) +{ + HANDLE fh; + BOOL status; + SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb; + SCSI_ADDRESS scsiAddr; + ULONG length; + ULONG returned; + BYTE inqData[NTSCSI_HA_INQUIRY_SIZE]; + +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, "SPTI: Checking drive %c:", 'A'+i); +#endif + + fh = GetFileHandle(i, TRUE); /* No NONSHARED Create for inquiry */ + + if (fh == INVALID_HANDLE_VALUE) { +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, " : fh == INVALID_HANDLE_VALUE\n"); +#endif + return; + } + +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, " : Index %d: fh == %08X\n", i, fh); +#endif + + + /* + * Get the drive inquiry data + */ + memset(&swb, 0, sizeof (swb)); + memset(inqData, 0, sizeof (inqData)); + swb.spt.Length = sizeof (SCSI_PASS_THROUGH_DIRECT); + swb.spt.CdbLength = 6; + swb.spt.SenseInfoLength = 24; + swb.spt.DataIn = SCSI_IOCTL_DATA_IN; + swb.spt.DataTransferLength = 100; + swb.spt.TimeOutValue = 2; + swb.spt.DataBuffer = inqData; + swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); + swb.spt.Cdb[0] = SCSI_CMD_INQUIRY; + swb.spt.Cdb[4] = NTSCSI_HA_INQUIRY_SIZE; + + length = sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER); + status = DeviceIoControl(fh, + IOCTL_SCSI_PASS_THROUGH_DIRECT, + &swb, + sizeof (swb), + &swb, + sizeof (swb), + &returned, + NULL); + + if (!status) { + CloseHandle(fh); +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, "SPTI: Error DeviceIoControl() -> %d\n", GetLastError()); +#endif + return; + } + + memcpy(pDrive->inqData, inqData, NTSCSI_HA_INQUIRY_SIZE); + + /* + * get the address (path/tgt/lun) of the drive via IOCTL_SCSI_GET_ADDRESS + */ + memset(&scsiAddr, 0, sizeof (SCSI_ADDRESS)); + scsiAddr.Length = sizeof (SCSI_ADDRESS); + if (DeviceIoControl(fh, IOCTL_SCSI_GET_ADDRESS, NULL, 0, + &scsiAddr, sizeof (SCSI_ADDRESS), &returned, + NULL)) { +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, "Device %c: Port=%d, PathId=%d, TargetId=%d, Lun=%d\n", + (char)i+'A', scsiAddr.PortNumber, scsiAddr.PathId, + scsiAddr.TargetId, scsiAddr.Lun); +#endif + pDrive->bUsed = TRUE; + pDrive->ha = scsiAddr.PortNumber; /* preliminary */ + pDrive->PortNumber = scsiAddr.PortNumber; + pDrive->PathId = scsiAddr.PathId; + pDrive->tgt = scsiAddr.TargetId; + pDrive->lun = scsiAddr.Lun; + pDrive->driveLetter = i; + pDrive->hDevice = INVALID_HANDLE_VALUE; + + } else if (GetLastError() == 50) { /* support USB/FIREWIRE devices where this call is not supported assign drive letter as device ID */ + pDrive->bUsed = TRUE; + pDrive->ha = i; + pDrive->PortNumber = i+64; /* hopefully no conflict with other PortNumber */ + pDrive->PathId = 0; + pDrive->tgt = 0; + pDrive->lun = 0; + pDrive->driveLetter = i; + pDrive->hDevice = INVALID_HANDLE_VALUE; +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, "USB/Firewire Device %c: Port=%d, TargetId=%d, Lun=%d\n", (char)i+'A', i, 0, 0); +#endif + } else { + pDrive->bUsed = FALSE; +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, "SPTI: Device %s: Error DeviceIoControl(): %d\n", (char)i+'A', GetLastError()); +#endif + CloseHandle(fh); + return; + } +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, "SPTI: Adding drive %c: (%d:%d:%d)\n", 'A'+i, + pDrive->ha, pDrive->tgt, pDrive->lun); +#endif + CloseHandle(fh); +} + + + +static DWORD +SPTIHandleHaInquiry(LPSRB_HAInquiry lpsrb) +{ + DWORD *pMTL; + + lpsrb->HA_Count = sptiglobal.numAdapters; + if (lpsrb->SRB_HaId >= sptiglobal.numAdapters) { + lpsrb->SRB_Status = SS_INVALID_HA; + return (SS_INVALID_HA); + } + lpsrb->HA_SCSI_ID = 7; /* who cares... we're not really an ASPI manager */ + memcpy(lpsrb->HA_ManagerId, "AKASPI v0.000001", 16); + memcpy(lpsrb->HA_Identifier, "SCSI Adapter ", 16); + lpsrb->HA_Identifier[13] = (char)('0'+lpsrb->SRB_HaId); + memset(lpsrb->HA_Unique, 0, 16); + lpsrb->HA_Unique[3] = 8; + pMTL = (LPDWORD)&lpsrb->HA_Unique[4]; + *pMTL = 64 * 1024; + + lpsrb->SRB_Status = SS_COMP; + return (SS_COMP); +} + +/* + * Looks up the index in the drive array for a given ha:tgt:lun triple + */ +static BYTE +SPTIGetDeviceIndex(BYTE ha, BYTE tgt, BYTE lun) +{ + BYTE i; + +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, "SPTI: SPTIGetDeviceIndex, %d, %d, %d\n", ha, + tgt, lun); +#endif + + for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++) { + if (sptiglobal.drive[i].bUsed) { + DRIVE *lpd; + + lpd = &sptiglobal.drive[i]; + if ((lpd->ha == ha) && (lpd->tgt == tgt) && (lpd->lun == lun)) + return (i); + } + } + + return (0); +} + +/* + * Converts ASPI-style SRB to SCSI Pass Through IOCTL + */ + +static DWORD +SPTIExecSCSICommand(LPSRB_ExecSCSICmd lpsrb, int sptTimeOutValue, BOOL bBeenHereBefore) +{ + BOOL status; + SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb; + ULONG length; + ULONG returned; + BYTE idx; + BYTE j; + + idx = SPTIGetDeviceIndex(lpsrb->SRB_HaId, lpsrb->SRB_Target, lpsrb->SRB_Lun); + + if (idx == 0) { + lpsrb->SRB_Status = SS_NO_DEVICE; + return (SS_NO_DEVICE); + } + + if (lpsrb->CDBByte[0] == SCSI_CMD_INQUIRY) { + lpsrb->SRB_Status = SS_COMP; + memcpy(lpsrb->SRB_BufPointer, sptiglobal.drive[idx].inqData, NTSCSI_HA_INQUIRY_SIZE); + return (SS_COMP); + } + + if (sptiglobal.drive[idx].hDevice == INVALID_HANDLE_VALUE) + sptiglobal.drive[idx].hDevice = GetFileHandle(sptiglobal.drive[idx].driveLetter, FALSE); + + memset(&swb, 0, sizeof (swb)); + swb.spt.Length = sizeof (SCSI_PASS_THROUGH); + swb.spt.CdbLength = lpsrb->SRB_CDBLen; + if (lpsrb->SRB_Flags & SRB_DIR_IN) + swb.spt.DataIn = SCSI_IOCTL_DATA_IN; + else if (lpsrb->SRB_Flags & SRB_DIR_OUT) + swb.spt.DataIn = SCSI_IOCTL_DATA_OUT; + else + swb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; + swb.spt.DataTransferLength = lpsrb->SRB_BufLen; + swb.spt.TimeOutValue = sptTimeOutValue; + swb.spt.SenseInfoLength = lpsrb->SRB_SenseLen; + swb.spt.DataBuffer = lpsrb->SRB_BufPointer; + swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); + memcpy(swb.spt.Cdb, lpsrb->CDBByte, lpsrb->SRB_CDBLen); + length = sizeof (swb); + +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, "SPTI: SPTIExecSCSICmd: calling DeviceIoControl()"); + fprintf(usalp_errfile, " : cmd == 0x%02X", swb.spt.Cdb[0]); +#endif + status = DeviceIoControl(sptiglobal.drive[idx].hDevice, + IOCTL_SCSI_PASS_THROUGH_DIRECT, + &swb, + length, + &swb, + length, + &returned, + NULL); + + lpsrb->SRB_SenseLen = swb.spt.SenseInfoLength; + memcpy(lpsrb->SenseArea, swb.ucSenseBuf, lpsrb->SRB_SenseLen); + if (status && swb.spt.ScsiStatus == 0) { + lpsrb->SRB_Status = SS_COMP; +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, " : SRB_Status == SS_COMP\n"); +#endif + } else { + DWORD dwErrCode; + + lpsrb->SRB_Status = SS_ERR; +/* lpsrb->SRB_TargStat = 0x0004;*/ + lpsrb->SRB_TargStat = swb.spt.ScsiStatus; + + dwErrCode = GetLastError(); +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, " : error == %d handle == %08X\n", dwErrCode, sptiglobal.drive[idx].hDevice); +#endif + /* + * KLUDGE ALERT! KLUDGE ALERT! KLUDGE ALERT! + * Whenever a disk changer switches disks, it may render the device + * handle invalid. We try to catch these errors here and recover + * from them. + */ + if (!bBeenHereBefore && + ((dwErrCode == ERROR_MEDIA_CHANGED) || (dwErrCode == ERROR_INVALID_HANDLE))) { + if (dwErrCode != ERROR_INVALID_HANDLE) + CloseHandle(sptiglobal.drive[idx].hDevice); + GetDriveInformation(idx, &sptiglobal.drive[idx]); + if (sptihamax > 0) { + if (sptiglobal.drive[idx].bUsed) + for (j = 0; j < sptihamax; j++) { + if (sptihasortarr[j] == + ((sptiglobal.drive[idx].PortNumber << 8) | sptiglobal.drive[idx].PathId)) { + sptiglobal.drive[idx].ha = j; + break; + } + } + } +#ifdef _DEBUG_SCSIPT + fprintf(usalp_errfile, "SPTI: SPTIExecSCSICommand: Retrying after ERROR_MEDIA_CHANGED\n"); +#endif + return (SPTIExecSCSICommand(lpsrb, sptTimeOutValue, TRUE)); + } + } + return (lpsrb->SRB_Status); +} +/* SPTI End -----------------------------------------------------------------*/ + + +static void +exit_func() +{ + if (!close_driver()) + errmsgno(EX_BAD, "Cannot close Win32-ASPI-Driver.\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: + if (UsingSPTI) + return (_usal_itrans_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", + "ASPI:", "bus,target,lun", "ASPI:1,2,0", TRUE, FALSE); + __usal_help(f, "SPTI", "Generic SCSI for Windows NT/2000/XP", + "SPTI:", "bus,target,lun", "SPTI: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); + + /*usal_local(usalp)->drive_wanted = NULL; + for(i=0;i<MAX_SCG*MAX_TGT*MAX_LUN;i++) + usallocal(usalp)->filenames[i]=NULL; + */ + usalp->local = calloc(1, sizeof (struct usal_local)); + if (usalp->local == NULL) + return (0); + + 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); + } + + /* Explicite choice of Schilling syntax */ + if (device != NULL && (strcmp(device, "SPTI") == 0 || strcmp(device, "ASPI") == 0)) + goto devok; + + /* use device as drive letter */ + 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); +*/ + + UsingSPTI = TRUE; + usallocal(usalp)->drive_wanted = *device; + + /* not the finest solution but prevents breaking on various + * places for no good reasons... */ + usal_scsibus(usalp)=0; + usal_target(usalp)=0; + usal_lun(usalp)=0; + goto openbydev; + } +devok: + if (DriverLoaded <= 0) { /* do not change access method on open driver */ + ForceAccess = FALSE; +#ifdef PREFER_SPTI + UsingSPTI = TRUE; +#else + UsingSPTI = FALSE; +#endif + if (!w2k_or_newer()) + UsingSPTI = FALSE; + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_open: Prefered SCSI transport: %s\n", + UsingSPTI ? "SPTI":"ASPI"); + } + if (device != NULL && strcmp(device, "SPTI") == 0) { + UsingSPTI = TRUE; + ForceAccess = TRUE; + } else if (device != NULL && strcmp(device, "ASPI") == 0) { + UsingSPTI = FALSE; + ForceAccess = TRUE; + } + if (device != NULL && usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_open: Selected SCSI transport: %s\n", + UsingSPTI ? "SPTI":"ASPI"); + } + } + + /* + * Check if variables are within the range + */ + if (tgt >= 0 && tgt >= 0 && tlun >= 0) { + /* + * This is the non -scanbus case. + */ + ; + } else if (tgt == -2 && tgt == -2 && + (tgt == -2 || tlun >= 0)) { + /* + * This is the dev=ASPI case. + */ + ; + } else if (tgt != -1 || tgt != -1 || tlun != -1) { + errno = EINVAL; + return (-1); + } + +openbydev: + /* + * Try to open ASPI-Router + */ + if (!open_driver(usalp)) + return (-1); + + /* + * More than we have ... + */ + if (busno >= busses) { + close_driver(); + return (-1); + } + + /* + * Install Exit Function which closes the ASPI-Router + */ + atexit(exit_func); + + /* + * Success after all + */ + return (1); +} + +static int +usalo_close(SCSI *usalp) +{ + int i; + /* + for(i=0;i<MAX_SCG*MAX_TGT*MAX_LUN;i++) { + if(usallocal(usalp)->filenames[i]) { + free(usallocal(usalp)->filenames[i]); + usallocal(usalp)->filenames[i]=NULL; + } + } + */ + if(usalp->local) { + free(usalp->local); + usalp->local=NULL; + } + //printf("closing\n"); + + exit_func(); + return (0); +} + +static long +usalo_maxdma(SCSI *usalp, long amt) +{ + return (MAX_DMA_WNT); +} + +static void * +usalo_getbuf(SCSI *usalp, long amt) +{ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "usalo_getbuf: %ld bytes\n", amt); + } + usalp->bufbase = malloc((size_t)(amt)); + return (usalp->bufbase); +} + +static void +usalo_freebuf(SCSI *usalp) +{ + if (usalp->bufbase) + free(usalp->bufbase); + usalp->bufbase = NULL; +} + +static __SBOOL +usalo_havebus(SCSI *usalp, int busno) +{ + if (busno < 0 || busno >= busses) + return (FALSE); + + return (TRUE); +} + +static int +usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun) +{ + if (busno < 0 || busno >= busses || + tgt < 0 || tgt >= MAX_TGT || + tlun < 0 || tlun >= MAX_LUN) + return (-1); + + /* + * Return fake + */ + return (1); +} + + +static int +usalo_initiator_id(SCSI *usalp) +{ + SRB_HAInquiry s; + + if (ha_inquiry(usalp, usal_scsibus(usalp), &s) < 0) + return (-1); + return (s.HA_SCSI_ID); +} + +static int +usalo_isatapi(SCSI *usalp) +{ + return (-1); /* XXX Need to add real test */ +} + + +/* + * XXX usalo_reset not yet tested + */ +static int +usalo_reset(SCSI *usalp, int what) +{ + + DWORD Status = 0; + DWORD EventStatus = WAIT_OBJECT_0; + HANDLE Event = NULL; + SRB_BusDeviceReset s; + + if (what == SCG_RESET_NOP) { + if (UsingSPTI) + return (-1); + else + return (0); /* Can ASPI really reset? */ + } + if (what != SCG_RESET_BUS) { + errno = EINVAL; + return (-1); + } + if (UsingSPTI) { + fprintf((FILE *)usalp->errfile, + "Reset SCSI device not implemented with SPTI\n"); + return (-1); + } + + /* + * XXX Does this reset TGT or BUS ??? + */ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Attempting to reset SCSI device\n"); + } + + /* + * Check if ASPI library is loaded + */ + if (DriverLoaded <= 0) { + fprintf((FILE *)usalp->errfile, + "error in usalo_reset: ASPI driver not loaded !\n"); + return (-1); + } + + memset(&s, 0, sizeof (s)); /* Clear SRB_BesDeviceReset structure */ + + Event = CreateEvent(NULL, TRUE, FALSE, NULL); + + /* + * Set structure variables + */ + s.SRB_Cmd = SC_RESET_DEV; /* ASPI command code = SC_RESET_DEV */ + s.SRB_HaId = usal_scsibus(usalp); /* ASPI host adapter number */ + s.SRB_Flags = SRB_EVENT_NOTIFY; /* Flags */ + s.SRB_Target = usal_target(usalp); /* Target's SCSI ID */ + s.SRB_Lun = usal_lun(usalp); /* Target's LUN number */ + s.SRB_PostProc = (LPVOID)Event; /* Post routine */ + + /* + * Initiate SCSI command + */ + Status = pfnSendASPI32Command((LPSRB)&s); + + /* + * Check status + */ + if (Status == SS_PENDING) { + /* + * Wait till command completes + */ + EventStatus = WaitForSingleObject(Event, INFINITE); + } + + + /**************************************************/ + /* Reset event to non-signaled state. */ + /**************************************************/ + + if (EventStatus == WAIT_OBJECT_0) { + /* + * Clear event + */ + ResetEvent(Event); + } + + /* + * Close the event handle + */ + CloseHandle(Event); + + /* + * Check condition + */ + if (s.SRB_Status != SS_COMP) { + fprintf((FILE *)usalp->errfile, + "ERROR! 0x%08X\n", s.SRB_Status); + + /* + * Indicate that error has occured + */ + return (-1); + } + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Reset SCSI device completed\n"); + } + + /* + * Everything went OK + */ + return (0); +} + + +#ifdef DEBUG_WNTASPI +static void +DebugScsiSend(SCSI *usalp, SRB_ExecSCSICmd *s, int bDisplayBuffer) +{ + int i; + + fprintf((FILE *)usalp->errfile, "\n\nDebugScsiSend\n"); + fprintf((FILE *)usalp->errfile, "s->SRB_Cmd = 0x%02x\n", s->SRB_Cmd); + fprintf((FILE *)usalp->errfile, "s->SRB_HaId = 0x%02x\n", s->SRB_HaId); + fprintf((FILE *)usalp->errfile, "s->SRB_Flags = 0x%02x\n", s->SRB_Flags); + fprintf((FILE *)usalp->errfile, "s->SRB_Target = 0x%02x\n", s->SRB_Target); + fprintf((FILE *)usalp->errfile, "s->SRB_Lun = 0x%02x\n", s->SRB_Lun); + fprintf((FILE *)usalp->errfile, "s->SRB_BufLen = 0x%02x\n", s->SRB_BufLen); + fprintf((FILE *)usalp->errfile, "s->SRB_BufPointer = %x\n", s->SRB_BufPointer); + fprintf((FILE *)usalp->errfile, "s->SRB_CDBLen = 0x%02x\n", s->SRB_CDBLen); + fprintf((FILE *)usalp->errfile, "s->SRB_SenseLen = 0x%02x\n", s->SRB_SenseLen); + fprintf((FILE *)usalp->errfile, "s->CDBByte ="); + for (i = 0; i < min(s->SRB_CDBLen, 16); i++) { + fprintf((FILE *)usalp->errfile, " %02X ", s->CDBByte[i]); + } + fprintf((FILE *)usalp->errfile, "\n"); + + /* + if (bDisplayBuffer != 0 && s->SRB_BufLen >= 8) { + + fprintf((FILE *)usalp->errfile, "s->SRB_BufPointer ="); + for (i = 0; i < 8; i++) { + fprintf((FILE *)usalp->errfile, + " %02X ", ((char *)s->SRB_BufPointer)[i]); + } + fprintf((FILE *)usalp->errfile, "\n"); + } +*/ + fprintf((FILE *)usalp->errfile, "Debug done\n"); +} +#endif + +static void +copy_sensedata(SRB_ExecSCSICmd *cp, struct usal_cmd *sp) +{ + sp->sense_count = cp->SRB_SenseLen; + if (sp->sense_count > sp->sense_len) + sp->sense_count = sp->sense_len; + + memset(&sp->u_sense.Sense, 0x00, sizeof (sp->u_sense.Sense)); + memcpy(&sp->u_sense.Sense, cp->SenseArea, sp->sense_count); + + sp->u_scb.cmd_scb[0] = cp->SRB_TargStat; +} + +/* + * Set error flags + */ +static void +set_error(SRB_ExecSCSICmd *cp, struct usal_cmd *sp) +{ + switch (cp->SRB_Status) { + + case SS_COMP: /* 0x01 SRB completed without error */ + sp->error = SCG_NO_ERROR; + sp->ux_errno = 0; + break; + + case SS_ERR: /* 0x04 SRB completed with error */ + /* + * If the SCSI Status byte is != 0, we definitely could send + * the command to the target. We signal NO transport error. + */ + sp->error = SCG_NO_ERROR; + sp->ux_errno = EIO; + if (cp->SRB_TargStat) + break; + + case SS_PENDING: /* 0x00 SRB being processed */ + /* + * XXX Could SS_PENDING happen ??? + */ + case SS_ABORTED: /* 0x02 SRB aborted */ + case SS_ABORT_FAIL: /* 0x03 Unable to abort SRB */ + default: + sp->error = SCG_RETRYABLE; + sp->ux_errno = EIO; + break; + + case SS_INVALID_CMD: /* 0x80 Invalid ASPI command */ + case SS_INVALID_HA: /* 0x81 Invalid host adapter number */ + case SS_NO_DEVICE: /* 0x82 SCSI device not installed */ + + case SS_INVALID_SRB: /* 0xE0 Invalid parameter set in SRB */ + case SS_ILLEGAL_MODE: /* 0xE2 Unsupported Windows mode */ + case SS_NO_ASPI: /* 0xE3 No ASPI managers */ + case SS_FAILED_INIT: /* 0xE4 ASPI for windows failed init */ + case SS_MISMATCHED_COMPONENTS: /* 0xE7 The DLLs/EXEs of ASPI don't */ + /* version check */ + case SS_NO_ADAPTERS: /* 0xE8 No host adapters to manager */ + + case SS_ASPI_IS_SHUTDOWN: /* 0xEA Call came to ASPI after */ + /* PROCESS_DETACH */ + case SS_BAD_INSTALL: /* 0xEB The DLL or other components */ + /* are installed wrong */ + sp->error = SCG_FATAL; + sp->ux_errno = EINVAL; + break; + +#ifdef XXX + case SS_OLD_MANAGER: /* 0xE1 ASPI manager doesn't support */ + /* windows */ +#endif + case SS_BUFFER_ALIGN: /* 0xE1 Buffer not aligned (replaces */ + /* SS_OLD_MANAGER in Win32) */ + sp->error = SCG_FATAL; + sp->ux_errno = EFAULT; + break; + + case SS_ASPI_IS_BUSY: /* 0xE5 No resources available to */ + /* execute command */ + sp->error = SCG_RETRYABLE; + sp->ux_errno = EBUSY; + break; + +#ifdef XXX + case SS_BUFFER_TO_BIG: /* 0xE6 Buffer size too big to handle*/ +#endif + case SS_BUFFER_TOO_BIG: /* 0xE6 Correct spelling of 'too' */ + case SS_INSUFFICIENT_RESOURCES: /* 0xE9 Couldn't allocate resources */ + /* needed to init */ + sp->error = SCG_RETRYABLE; + sp->ux_errno = ENOMEM; + break; + } +} + + +struct aspi_cmd { + SRB_ExecSCSICmd s; + char pad[32]; +}; + +static int +usalo_send(SCSI *usalp) +{ + struct usal_cmd *sp = usalp->scmd; + DWORD Status = 0; + DWORD EventStatus = WAIT_OBJECT_0; + HANDLE Event = NULL; + struct aspi_cmd ac; + SRB_ExecSCSICmd *s; + + s = &ac.s; + + /* + * Check if ASPI library is loaded + */ + if (DriverLoaded <= 0) { + errmsgno(EX_BAD, "error in usalo_send: ASPI driver not loaded.\n"); + sp->error = SCG_FATAL; + return (0); + } + + if (usalp->fd < 0) { + sp->error = SCG_FATAL; + return (-1); + } + + /* + * Initialize variables + */ + sp->error = SCG_NO_ERROR; + sp->sense_count = 0; + sp->u_scb.cmd_scb[0] = 0; + sp->resid = 0; + + memset(&ac, 0, sizeof (ac)); /* Clear SRB structure */ + + /* + * Check cbd_len > the maximum command pakket that can be handled by ASPI + */ + if (sp->cdb_len > 16) { + sp->error = SCG_FATAL; + sp->ux_errno = EINVAL; + fprintf((FILE *)usalp->errfile, + "sp->cdb_len > sizeof (SRB_ExecSCSICmd.CDBByte). Fatal error in usalo_send, exiting...\n"); + return (-1); + } + /* + * copy cdrecord command into SRB + */ + movebytes(&sp->cdb, &(s->CDBByte), sp->cdb_len); + + Event = CreateEvent(NULL, TRUE, FALSE, NULL); + + /* + * Fill ASPI structure + */ + s->SRB_Cmd = SC_EXEC_SCSI_CMD; /* SCSI Command */ + s->SRB_HaId = usal_scsibus(usalp); /* Host adapter number */ + s->SRB_Flags = SRB_EVENT_NOTIFY; /* Flags */ + s->SRB_Target = usal_target(usalp); /* Target SCSI ID */ + s->SRB_Lun = usal_lun(usalp); /* Target SCSI LUN */ + s->SRB_BufLen = sp->size; /* # of bytes transferred */ + s->SRB_BufPointer = sp->addr; /* pointer to data buffer */ + s->SRB_CDBLen = sp->cdb_len; /* SCSI command length */ + s->SRB_PostProc = Event; /* Post proc event */ + if (UsingSPTI) + s->SRB_SenseLen = SENSE_LEN_SPTI; /* Length of sense buffer, SPTI returns SenseInfoLength */ + else + s->SRB_SenseLen = SENSE_LEN; /* fixed length 14 for ASPI */ + /* + * Do we receive data from this ASPI command? + */ + if (sp->flags & SCG_RECV_DATA) { + + s->SRB_Flags |= SRB_DIR_IN; + } else { + /* + * Set direction to output + */ + if (sp->size > 0) { + s->SRB_Flags |= SRB_DIR_OUT; + } + } + +#ifdef DEBUG_WNTASPI + /* + * Dump some debug information when enabled + */ + DebugScsiSend(usalp, s, TRUE); +/* DebugScsiSend(usalp, s, (s->SRB_Flags&SRB_DIR_OUT) == SRB_DIR_OUT);*/ +#endif + + /* + * ------------ Send SCSI command -------------------------- + */ + + ResetEvent(Event); /* Clear event handle */ + if (UsingSPTI) { +#ifdef _DEBUG_SCSIPT + usalp_errfile = (FILE *)usalp->errfile; +#endif + Status = SPTIExecSCSICommand(s, sp->timeout, FALSE); + } + else + Status = pfnSendASPI32Command((LPSRB)s); /* Initiate SCSI command */ + if (Status == SS_PENDING) { /* If in progress */ + /* + * Wait untill command completes, or times out. + */ + EventStatus = WaitForSingleObject(Event, sp->timeout*1000L); +/* EventStatus = WaitForSingleObject(Event, 10L);*/ + + if (EventStatus == WAIT_OBJECT_0) + ResetEvent(Event); /* Clear event, time out */ + + if (s->SRB_Status == SS_PENDING) { /* Check if we got a timeout */ + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Timeout....\n"); + } + scsiabort(usalp, s); + ResetEvent(Event); /* Clear event, time out */ + CloseHandle(Event); /* Close the event handle */ + + sp->error = SCG_TIMEOUT; + return (1); /* Return error */ + } + } + CloseHandle(Event); /* Close the event handle */ + + /* + * Check ASPI command status + */ + if (s->SRB_Status != SS_COMP) { + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Error in usalo_send: s->SRB_Status is 0x%x\n", s->SRB_Status); + } + + set_error(s, sp); /* Set error flags */ + copy_sensedata(s, sp); /* Copy sense and status */ + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Mapped to: error %d errno: %d\n", sp->error, sp->ux_errno); + } + return (1); + } + + /* + * Return success + */ + return (0); +} + +/*************************************************************************** + * * + * 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) +{ + DWORD astatus; + BYTE HACount; + BYTE ASPIStatus; + int i; + +#ifdef DEBUG_WNTASPI + fprintf((FILE *)usalp->errfile, "enter open_driver\n"); +#endif + + /* + * Check if ASPI library is already loaded yet + */ + if (DriverLoaded > 0) { + DriverLoaded++; + return (TRUE); + } + + /* + * Load the ASPI library or SPTI + */ +#ifdef _DEBUG_SCSIPT + usalp_errfile = (FILE *)usalp->errfile; +#endif +#ifdef PREFER_SPTI + if (UsingSPTI) + if (InitSCSIPT(usalp) > 0) DriverLoaded++; +#endif +#ifdef PREFER_SPTI + if ((!UsingSPTI || !ForceAccess) && DriverLoaded <= 0) { +#else + if (!UsingSPTI || !ForceAccess) { +#endif + if (load_aspi(usalp)) { + DriverLoaded++; + UsingSPTI = FALSE; + } + } + +#ifndef PREFER_SPTI + if ((UsingSPTI || !ForceAccess) && DriverLoaded <= 0) + if (InitSCSIPT(usalp) > 0) + DriverLoaded++; +#endif /*PREFER_SPTI*/ + + if (DriverLoaded <= 0) { + if (UsingSPTI) { + if (errno == 0) + errno = ENOSYS; + } + fprintf((FILE *)usalp->errfile, "Can not load %s driver! ", + UsingSPTI ? "SPTI":"ASPI"); + return (FALSE); + } + + if (UsingSPTI) { + if (usalp->debug > 0) + fprintf((FILE *)usalp->errfile, "using SPTI Transport\n"); + + if (!sptiglobal.numAdapters) + astatus = (DWORD)(MAKEWORD(0, SS_NO_ADAPTERS)); + else + astatus = (DWORD)(MAKEWORD(sptiglobal.numAdapters, SS_COMP)); + } else { + astatus = pfnGetASPI32SupportInfo(); + } + + ASPIStatus = HIBYTE(LOWORD(astatus)); + HACount = LOBYTE(LOWORD(astatus)); + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "open_driver %lX HostASPIStatus=0x%x HACount=0x%x\n", astatus, ASPIStatus, HACount); + } + + if (ASPIStatus != SS_COMP && ASPIStatus != SS_NO_ADAPTERS) { + fprintf((FILE *)usalp->errfile, "Could not find any host adapters\n"); + fprintf((FILE *)usalp->errfile, "ASPIStatus == 0x%02X", ASPIStatus); + return (FALSE); + } + busses = HACount; + +#ifdef DEBUG_WNTASPI + fprintf((FILE *)usalp->errfile, "open_driver HostASPIStatus=0x%x HACount=0x%x\n", ASPIStatus, HACount); + fprintf((FILE *)usalp->errfile, "leaving open_driver\n"); +#endif + + for (i = 0; i < busses; i++) { + SRB_HAInquiry s; + + ha_inquiry(usalp, i, &s); + } + + /* + * Indicate that library loaded/initialized properly + */ + return (TRUE); +} + +static BOOL +load_aspi(SCSI *usalp) +{ +#ifdef __CYGWIN32__ + hAspiLib = dlopen("WNASPI32", RTLD_NOW); +#else + hAspiLib = LoadLibrary("WNASPI32"); +#endif + /* + * Check if ASPI library is loaded correctly + */ + if (hAspiLib == NULL) { +#ifdef not_done_later + fprintf((FILE *)usalp->errfile, "Can not load ASPI driver! "); +#endif + return (FALSE); + } + + /* + * Get a pointer to GetASPI32SupportInfo function + * and a pointer to SendASPI32Command function + */ +#ifdef __CYGWIN32__ + pfnGetASPI32SupportInfo = (DWORD(*)(void))dlsym(hAspiLib, "GetASPI32SupportInfo"); + pfnSendASPI32Command = (DWORD(*)(LPSRB))dlsym(hAspiLib, "SendASPI32Command"); +#else + pfnGetASPI32SupportInfo = (DWORD(*)(void))GetProcAddress(hAspiLib, "GetASPI32SupportInfo"); + pfnSendASPI32Command = (DWORD(*)(LPSRB))GetProcAddress(hAspiLib, "SendASPI32Command"); +#endif + + if ((pfnGetASPI32SupportInfo == NULL) || (pfnSendASPI32Command == NULL)) { + fprintf((FILE *)usalp->errfile, + "ASPI function not found in library! "); + return (FALSE); + } + + /* + * The following functions are currently not used by libusal. + * If we start to use them, we need to check whether the founctions + * could be found in the ASPI library that just has been loaded. + */ +#ifdef __CYGWIN32__ + pfnGetASPI32Buffer = (BOOL(*)(PASPI32BUFF))dlsym(hAspiLib, "GetASPI32Buffer"); + pfnFreeASPI32Buffer = (BOOL(*)(PASPI32BUFF))dlsym(hAspiLib, "FreeASPI32Buffer"); + pfnTranslateASPI32Address = (BOOL(*)(PDWORD, PDWORD))dlsym(hAspiLib, "TranslateASPI32Address"); +#else + pfnGetASPI32Buffer = (BOOL(*)(PASPI32BUFF))GetProcAddress(hAspiLib, "GetASPI32Buffer"); + pfnFreeASPI32Buffer = (BOOL(*)(PASPI32BUFF))GetProcAddress(hAspiLib, "FreeASPI32Buffer"); + pfnTranslateASPI32Address = (BOOL(*)(PDWORD, PDWORD))GetProcAddress(hAspiLib, "TranslateASPI32Address"); +#endif + 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() +{ + if (--DriverLoaded > 0) + return (TRUE); + /* + * If library is loaded + */ + DeinitSCSIPT(); + /* + * Clear all variables + */ + if (hAspiLib) { + pfnGetASPI32SupportInfo = NULL; + pfnSendASPI32Command = NULL; + pfnGetASPI32Buffer = NULL; + pfnFreeASPI32Buffer = NULL; + pfnTranslateASPI32Address = NULL; + + /* + * Free ASPI library, we do not need it any longer + */ +#ifdef __CYGWIN32__ + dlclose(hAspiLib); +#else + FreeLibrary(hAspiLib); +#endif + hAspiLib = NULL; + } + + /* + * Indicate that shutdown has been finished properly + */ + return (TRUE); +} + +static int +ha_inquiry(SCSI *usalp, int id, SRB_HAInquiry *ip) +{ + DWORD Status; + + ip->SRB_Cmd = SC_HA_INQUIRY; + ip->SRB_HaId = id; + ip->SRB_Flags = 0; + ip->SRB_Hdr_Rsvd = 0; + + if (UsingSPTI) + Status = SPTIHandleHaInquiry(ip); + else + Status = pfnSendASPI32Command((LPSRB)ip); + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, "Status : %ld\n", Status); + fprintf((FILE *)usalp->errfile, "hacount: %d\n", ip->HA_Count); + fprintf((FILE *)usalp->errfile, "SCSI id: %d\n", ip->HA_SCSI_ID); + fprintf((FILE *)usalp->errfile, "Manager: '%.16s'\n", ip->HA_ManagerId); + fprintf((FILE *)usalp->errfile, "Identif: '%.16s'\n", ip->HA_Identifier); + usal_prbytes("Unique:", ip->HA_Unique, 16); + } + if (ip->SRB_Status != SS_COMP) + return (-1); + return (0); +} + +#ifdef __USED__ +static int +resetSCSIBus(SCSI *usalp) +{ + DWORD Status; + HANDLE Event; + SRB_BusDeviceReset s; + + if (UsingSPTI) { + fprintf((FILE *)usalp->errfile, + "Reset SCSI bus not implemented with SPTI\n"); + return (FALSE); + } + + fprintf((FILE *)usalp->errfile, "Attempting to reset SCSI bus\n"); + + Event = CreateEvent(NULL, TRUE, FALSE, NULL); + + memset(&s, 0, sizeof (s)); /* Clear SRB_BesDeviceReset structure */ + + /* + * Set structure variables + */ + s.SRB_Cmd = SC_RESET_DEV; + s.SRB_PostProc = (LPVOID)Event; + + /* + * Clear event + */ + ResetEvent(Event); + + /* + * Initiate SCSI command + */ + Status = pfnSendASPI32Command((LPSRB)&s); + + /* + * Check status + */ + if (Status == SS_PENDING) { + /* + * Wait till command completes + */ + WaitForSingleObject(Event, INFINITE); + } + + /* + * Close the event handle + */ + CloseHandle(Event); + + /* + * Check condition + */ + if (s.SRB_Status != SS_COMP) { + fprintf((FILE *)usalp->errfile, "ERROR 0x%08X\n", s.SRB_Status); + + /* + * Indicate that error has occured + */ + return (FALSE); + } + + /* + * Everything went OK + */ + return (TRUE); +} +#endif /* __USED__ */ + +static int +scsiabort(SCSI *usalp, SRB_ExecSCSICmd *sp) +{ + DWORD Status = 0; + SRB_Abort s; + + if (UsingSPTI) { + fprintf((FILE *)usalp->errfile, + "Abort SCSI not implemented with SPTI\n"); + return (FALSE); + } + + if (usalp->debug > 0) { + fprintf((FILE *)usalp->errfile, + "Attempting to abort SCSI command\n"); + } + + /* + * Check if ASPI library is loaded + */ + if (DriverLoaded <= 0) { + fprintf((FILE *)usalp->errfile, + "error in scsiabort: ASPI driver not loaded !\n"); + return (FALSE); + } + + /* + * Set structure variables + */ + s.SRB_Cmd = SC_ABORT_SRB; /* ASPI command code = SC_ABORT_SRB */ + s.SRB_HaId = usal_scsibus(usalp); /* ASPI host adapter number */ + s.SRB_Flags = 0; /* Flags */ + s.SRB_ToAbort = (LPSRB)&sp; /* sp */ + + /* + * Initiate SCSI abort + */ + Status = pfnSendASPI32Command((LPSRB)&s); + + /* + * Check condition + */ + if (s.SRB_Status != SS_COMP) { + fprintf((FILE *)usalp->errfile, "Abort ERROR! 0x%08X\n", s.SRB_Status); + + /* + * Indicate that error has occured + */ + return (FALSE); + } + + if (usalp->debug > 0) + fprintf((FILE *)usalp->errfile, "Abort SCSI command completed\n"); + + /* + * Everything went OK + */ + return (TRUE); +} + + +#define HAVE_NAT_NAMES +static char * usalo_natname(SCSI *usalp, int busno, int tgt, int tlun) { + int i; + static char name[3]; + printf("hm, %d, %d, %d\n", busno, tgt, tlun); + if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) + return "BADID"; + for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++) { + if(sptiglobal.drive[i].bUsed && + tlun == sptiglobal.drive[i].lun && + tgt == sptiglobal.drive[i].tgt && + busno == sptiglobal.drive[i].ha) + { + snprintf(name, 3, "%c:", 'A'+sptiglobal.drive[i].driveLetter); + return name; + } + } + return "BADID"; +} + diff --git a/libusal/scsierrs.c b/libusal/scsierrs.c new file mode 100644 index 0000000..154e418 --- /dev/null +++ b/libusal/scsierrs.c @@ -0,0 +1,1008 @@ +/* + * 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. + * + */ + +/* @(#)scsierrs.c 2.29 04/06/17 Copyright 1987-1996 J. Schilling */ +/* + * Error printing for scsitransp.c + * + * Copyright (c) 1987-1996 J. Schilling + */ +/* + * 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. + */ + +#include <mconfig.h> + +#include <stdio.h> +#include <unixstd.h> /* for sys/types.h needed in schily.h for sprintf() */ +#include <standard.h> +#include <schily.h> + +#include <usal/scsireg.h> +#include <usal/scsidefs.h> +#include <usal/usalcmd.h> /*XXX JS wird eigentlich nicht benoetigt!! */ + /*XXX JS kommt weg, wenn struct sense und status */ + /*XXX JS von usalio.h nach scsireg.h kommen */ +#include <usal/scsitransp.h> + +#define CTYPE_CCS 0 +#define CTYPE_MD21 1 +#define CTYPE_ACB4000 2 +#define CTYPE_SMO_C501 3 + +#define SMO_C501 + +const char *usal_sensemsg(int, int, int, const char **, char *, int maxcnt); +int usal__errmsg(SCSI *usalp, char *obuf, int maxcnt, struct scsi_sense *, + struct scsi_status *, int); +#if 0 +/* + * Map old non extended sense to sense key. + */ +static Uchar sd_adaptec_keys[] = { + 0, 4, 4, 4, 2, 2, 4, 4, /* 0x00-0x07 */ + 4, 4, 4, 4, 4, 4, 4, 4, /* 0x08-0x0f */ + 4, 3, 3, 3, 3, 4, 3, 1, /* 0x10-0x17 */ + 1, 1, 3, 4, 3, 4, 3, 3, /* 0x18-0x1f */ + 5, 5, 5, 5, 5, 5, 5, 7, /* 0x20-0x27 */ + 6, 6, 6, 5, 4,11,11,11 /* 0x28-0x2f */ +}; +#define MAX_ADAPTEC_KEYS (sizeof (sd_adaptec_keys)) +#endif + +/* + * Deviations to CCS found on old pre CCS devices + */ +static const char *sd_adaptec_error_str[] = { + "\031\000ECC error during verify", /* 0x19 */ + "\032\000interleave error", /* 0x1a */ + "\034\000bad format on drive", /* 0x1c */ + "\035\000self test failed", /* 0x1d */ + "\036\000defective track", /* 0x1e */ + "\043\000volume overflow", /* 0x23 */ + "\053\000set limit violation", /* 0x2b */ + "\054\000error counter overflow", /* 0x2c */ + "\055\000initiator detected error", /* 0x2d */ + "\056\000scsi parity error", /* 0x2e */ + "\057\000adapter parity error", /* 0x2f */ + NULL +}; + +/* + * The sense codes of SCSI-1/CCS, SCSI-2 and SCSI-3 devices. + */ +static const char *sd_ccs_error_str[] = { + "\000\000no additional sense information", /* 00 00 */ + "\000\001filemark detected", /* 00 01 */ + "\000\002end-of-partition/medium detected", /* 00 02 */ + "\000\003setmark detected", /* 00 03 */ + "\000\004beginning-of-partition/medium detected", /* 00 04 */ + "\000\005end-of-data detected", /* 00 05 */ + "\000\006i/o process terminated", /* 00 06 */ + "\000\021audio play operation in progress", /* 00 11 */ + "\000\022audio play operation paused", /* 00 12 */ + "\000\023audio play operation successfully completed", /* 00 13 */ + "\000\024audio play operation stopped due to error", /* 00 14 */ + "\000\025no current audio status to return", /* 00 15 */ + "\000\026operation in progress", /* 00 16 */ + "\000\027cleaning requested", /* 00 17 */ + "\001\000no index/sector signal", /* 01 00 */ + "\002\000no seek complete", /* 02 00 */ + "\003\000peripheral device write fault", /* 03 00 */ + "\003\001no write current", /* 03 01 */ + "\003\002excessive write errors", /* 03 02 */ + "\004\000logical unit not ready, cause not reportable", /* 04 00 */ + "\004\001logical unit is in process of becoming ready", /* 04 01 */ + "\004\002logical unit not ready, initializing cmd. required", /* 04 02 */ + "\004\003logical unit not ready, manual intervention required", /* 04 03 */ + "\004\004logical unit not ready, format in progress", /* 04 04 */ + "\004\005logical unit not ready, rebuild in progress", /* 04 05 */ + "\004\006logical unit not ready, recalculation in progress", /* 04 06 */ + "\004\007logical unit not ready, operation in progress",/* 04 07 */ + "\004\010logical unit not ready, long write in progress", /* 04 08 */ + "\004\011logical unit not ready, self-test in progress",/* 04 09 */ + "\004\012asymmetric access code 3 (00-232) [proposed]", /* 04 0A */ + "\004\013asymmetric access code 1 (00-232) [proposed]", /* 04 0B */ + "\004\014asymmetric access code 2 (00-232) [proposed]", /* 04 0C */ + "\004\020auxiliary memory code 2 (99-148) [proposed]", /* 04 10 */ + "\005\000logical unit does not respond to selection", /* 05 00 */ + "\006\000no reference position found", /* 06 00 */ + "\007\000multiple peripheral devices selected", /* 07 00 */ + "\010\000logical unit communication failure", /* 08 00 */ + "\010\001logical unit communication time-out", /* 08 01 */ + "\010\002logical unit communication parity error", /* 08 02 */ + "\010\003logical unit communication crc error (ultra-dma/32)", /* 08 03 */ + "\010\004unreachable copy target", /* 08 04 */ + "\011\000track following error", /* 09 00 */ + "\011\001tracking servo failure", /* 09 01 */ + "\011\002focus servo failure", /* 09 02 */ + "\011\003spindle servo failure", /* 09 03 */ + "\011\004head select fault", /* 09 04 */ + "\012\000error log overflow", /* 0A 00 */ + "\013\000warning", /* 0B 00 */ + "\013\001warning - specified temperature exceeded", /* 0B 01 */ + "\013\002warning - enclosure degraded", /* 0B 02 */ + "\014\000write error", /* 0C 00 */ + "\014\001write error - recovered with auto reallocation", /* 0C 01 */ + "\014\002write error - auto reallocation failed", /* 0C 02 */ + "\014\003write error - recommend reassignment", /* 0C 03 */ + "\014\004compression check miscompare error", /* 0C 04 */ + "\014\005data expansion occurred during compression", /* 0C 05 */ + "\014\006block not compressible", /* 0C 06 */ + "\014\007write error - recovery needed", /* 0C 07 */ + "\014\010write error - recovery failed", /* 0C 08 */ + "\014\011write error - loss of streaming", /* 0C 09 */ + "\014\012write error - padding blocks added", /* 0C 0A */ + "\014\013auxiliary memory code 4 (99-148) [proposed]", /* 0C 0B */ + "\015\000error detected by third party temporary initiator", /* 0D 00 */ + "\015\001third party device failure", /* 0D 01 */ + "\015\002copy target device not reachable", /* 0D 02 */ + "\015\003incorrect copy target device type", /* 0D 03 */ + "\015\004copy target device data underrun", /* 0D 04 */ + "\015\005copy target device data overrun", /* 0D 05 */ +#ifdef __used__ + "\016\000", /* 0E 00 */ + "\017\000", /* 0F 00 */ +#endif + "\020\000id crc or ecc error", /* 10 00 */ + "\021\000unrecovered read error", /* 11 00 */ + "\021\001read retries exhausted", /* 11 01 */ + "\021\002error too long to correct", /* 11 02 */ + "\021\003multiple read errors", /* 11 03 */ + "\021\004unrecovered read error - auto reallocate failed", /* 11 04 */ + "\021\005l-ec uncorrectable error", /* 11 05 */ + "\021\006circ unrecovered error", /* 11 06 */ + "\021\007data re-synchronization error", /* 11 07 */ + "\021\010incomplete block read", /* 11 08 */ + "\021\011no gap found", /* 11 09 */ + "\021\012miscorrected error", /* 11 0A */ + "\021\013unrecovered read error - recommend reassignment", /* 11 0B */ + "\021\014unrecovered read error - recommend rewrite the data", /* 11 0C */ + "\021\015de-compression crc error", /* 11 0D */ + "\021\016cannot decompress using declared algorithm", /* 11 0E */ + "\021\017error reading upc/ean number", /* 11 0F */ + "\021\020error reading isrc number", /* 11 10 */ + "\021\021read error - loss of streaming", /* 11 11 */ + "\021\022auxiliary memory code 3 (99-148) [proposed]", /* 11 12 */ + "\022\000address mark not found for id field", /* 12 00 */ + "\023\000address mark not found for data field", /* 13 00 */ + "\024\000recorded entity not found", /* 14 00 */ + "\024\001record not found", /* 14 01 */ + "\024\002filemark or setmark not found", /* 14 02 */ + "\024\003end-of-data not found", /* 14 03 */ + "\024\004block sequence error", /* 14 04 */ + "\024\005record not found - recommend reassignment", /* 14 05 */ + "\024\006record not found - data auto-reallocated", /* 14 06 */ + "\025\000random positioning error", /* 15 00 */ + "\025\001mechanical positioning error", /* 15 01 */ + "\025\002positioning error detected by read of medium", /* 15 02 */ + "\026\000data synchronization mark error", /* 16 00 */ + "\026\001data sync error - data rewritten", /* 16 01 */ + "\026\002data sync error - recommend rewrite", /* 16 02 */ + "\026\003data sync error - data auto-reallocated", /* 16 03 */ + "\026\004data sync error - recommend reassignment", /* 16 04 */ + "\027\000recovered data with no error correction applied", /* 17 00 */ + "\027\001recovered data with retries", /* 17 01 */ + "\027\002recovered data with positive head offset", /* 17 02 */ + "\027\003recovered data with negative head offset", /* 17 03 */ + "\027\004recovered data with retries and/or circ applied", /* 17 04 */ + "\027\005recovered data using previous sector id", /* 17 05 */ + "\027\006recovered data without ecc - data auto-reallocated", /* 17 06 */ + "\027\007recovered data without ecc - recommend reassignment", /* 17 07 */ + "\027\010recovered data without ecc - recommend rewrite", /* 17 08 */ + "\027\011recovered data without ecc - data rewritten", /* 17 09 */ + "\030\000recovered data with error correction applied", /* 18 00 */ + "\030\001recovered data with error corr. & retries applied", /* 18 01 */ + "\030\002recovered data - data auto-reallocated", /* 18 02 */ + "\030\003recovered data with circ", /* 18 03 */ + "\030\004recovered data with l-ec", /* 18 04 */ + "\030\005recovered data - recommend reassignment", /* 18 05 */ + "\030\006recovered data - recommend rewrite", /* 18 06 */ + "\030\007recovered data with ecc - data rewritten", /* 18 07 */ + "\030\010recovered data with linking", /* 18 08 */ + "\031\000defect list error", /* 19 00 */ + "\031\001defect list not available", /* 19 01 */ + "\031\002defect list error in primary list", /* 19 02 */ + "\031\003defect list error in grown list", /* 19 03 */ + "\032\000parameter list length error", /* 1A 00 */ + "\033\000synchronous data transfer error", /* 1B 00 */ + "\034\000defect list not found", /* 1C 00 */ + "\034\001primary defect list not found", /* 1C 01 */ + "\034\002grown defect list not found", /* 1C 02 */ + "\035\000miscompare during verify operation", /* 1D 00 */ + "\036\000recovered id with ecc correction", /* 1E 00 */ + "\037\000partial defect list transfer", /* 1F 00 */ + "\040\000invalid command operation code", /* 20 00 */ + "\040\001access controls code 1 (99-314) [proposed]", /* 20 01 */ + "\040\002access controls code 2 (99-314) [proposed]", /* 20 02 */ + "\040\003access controls code 3 (99-314) [proposed]", /* 20 03 */ + "\040\004read type operation while in write capable state", /* 20 04 */ + "\040\005write type operation while in read capable state", /* 20 05 */ + "\040\006illegal command while in explicit address model", /* 20 06 */ + "\040\007illegal command while in implicit address model", /* 20 07 */ + "\040\010access controls code 5 (99-245) [proposed]", /* 20 08 */ + "\040\011access controls code 6 (99-245) [proposed]", /* 20 09 */ + "\040\012access controls code 7 (99-245) [proposed]", /* 20 0A */ + "\040\013access controls code 8 (99-245) [proposed]", /* 20 0B */ + "\041\000logical block address out of range", /* 21 00 */ + "\041\001invalid element address", /* 21 01 */ + "\041\002invalid address for write", /* 21 02 */ + "\042\000illegal function (use 20 00, 24 00, or 26 00)",/* 22 00 */ +#ifdef __used__ + "\043\000", /* 23 00 */ +#endif + "\044\000invalid field in cdb", /* 24 00 */ + "\044\001cdb decryption error", /* 24 01 */ + "\044\002invalid cdb field while in explicit block address model", /* 24 02 */ + "\044\003invalid cdb field while in implicit block address model", /* 24 03 */ + "\045\000logical unit not supported", /* 25 00 */ + "\046\000invalid field in parameter list", /* 26 00 */ + "\046\001parameter not supported", /* 26 01 */ + "\046\002parameter value invalid", /* 26 02 */ + "\046\003threshold parameters not supported", /* 26 03 */ + "\046\004invalid release of persistent reservation", /* 26 04 */ + "\046\005data decryption error", /* 26 05 */ + "\046\006too many target descriptors", /* 26 06 */ + "\046\007unsupported target descriptor type code", /* 26 07 */ + "\046\010too many segment descriptors", /* 26 08 */ + "\046\011unsupported segment descriptor type code", /* 26 09 */ + "\046\012unexpected inexact segment", /* 26 0A */ + "\046\013inline data length exceeded", /* 26 0B */ + "\046\014invalid operation for copy source or destination", /* 26 0C */ + "\046\015copy segment granularity violation", /* 26 0D */ + "\047\000write protected", /* 27 00 */ + "\047\001hardware write protected", /* 27 01 */ + "\047\002logical unit software write protected", /* 27 02 */ + "\047\003associated write protect", /* 27 03 */ + "\047\004persistent write protect", /* 27 04 */ + "\047\005permanent write protect", /* 27 05 */ + "\047\006conditional write protect", /* 27 06 */ + "\050\000not ready to ready change, medium may have changed", /* 28 00 */ + "\050\001import or export element accessed", /* 28 01 */ + "\051\000power on, reset, or bus device reset occurred",/* 29 00 */ + "\051\001power on occurred", /* 29 01 */ + "\051\002scsi bus reset occurred", /* 29 02 */ + "\051\003bus device reset function occurred", /* 29 03 */ + "\051\004device internal reset", /* 29 04 */ + "\051\005transceiver mode changed to single-ended", /* 29 05 */ + "\051\006transceiver mode changed to lvd", /* 29 06 */ + "\052\000parameters changed", /* 2A 00 */ + "\052\001mode parameters changed", /* 2A 01 */ + "\052\002log parameters changed", /* 2A 02 */ + "\052\003reservations preempted", /* 2A 03 */ + "\052\004reservations released", /* 2A 04 */ + "\052\005registrations preempted", /* 2A 05 */ + "\052\006asymmetric access code 6 (00-232) [proposed]", /* 2A 06 */ + "\052\007asymmetric access code 7 (00-232) [proposed]", /* 2A 07 */ + "\053\000copy cannot execute since host cannot disconnect", /* 2B 00 */ + "\054\000command sequence error", /* 2C 00 */ + "\054\001too many windows specified", /* 2C 01 */ + "\054\002invalid combination of windows specified", /* 2C 02 */ + "\054\003current program area is not empty", /* 2C 03 */ + "\054\004current program area is empty", /* 2C 04 */ + "\054\005illegal power condition request", /* 2C 05 */ + "\054\006persistent prevent conflict", /* 2C 06 */ + "\055\000overwrite error on update in place", /* 2D 00 */ + "\056\000insufficient time for operation", /* 2E 00 */ + "\057\000commands cleared by another initiator", /* 2F 00 */ + "\060\000incompatible medium installed", /* 30 00 */ + "\060\001cannot read medium - unknown format", /* 30 01 */ + "\060\002cannot read medium - incompatible format", /* 30 02 */ + "\060\003cleaning cartridge installed", /* 30 03 */ + "\060\004cannot write medium - unknown format", /* 30 04 */ + "\060\005cannot write medium - incompatible format", /* 30 05 */ + "\060\006cannot format medium - incompatible medium", /* 30 06 */ + "\060\007cleaning failure", /* 30 07 */ + "\060\010cannot write - application code mismatch", /* 30 08 */ + "\060\011current session not fixated for append", /* 30 09 */ + "\060\020medium not formatted", /* 30 10 */ + "\061\000medium format corrupted", /* 31 00 */ + "\061\001format command failed", /* 31 01 */ + "\061\002zoned formatting failed due to spare linking", /* 31 02 */ + "\062\000no defect spare location available", /* 32 00 */ + "\062\001defect list update failure", /* 32 01 */ + "\063\000tape length error", /* 33 00 */ + "\064\000enclosure failure", /* 34 00 */ + "\065\000enclosure services failure", /* 35 00 */ + "\065\001unsupported enclosure function", /* 35 01 */ + "\065\002enclosure services unavailable", /* 35 02 */ + "\065\003enclosure services transfer failure", /* 35 03 */ + "\065\004enclosure services transfer refused", /* 35 04 */ + "\066\000ribbon, ink, or toner failure", /* 36 00 */ + "\067\000rounded parameter", /* 37 00 */ + "\070\000event status notification", /* 38 00 */ + "\070\002esn - power management class event", /* 38 02 */ + "\070\004esn - media class event", /* 38 04 */ + "\070\006esn - device busy class event", /* 38 06 */ + "\071\000saving parameters not supported", /* 39 00 */ + "\072\000medium not present", /* 3A 00 */ + "\072\001medium not present - tray closed", /* 3A 01 */ + "\072\002medium not present - tray open", /* 3A 02 */ + "\072\003medium not present - loadable", /* 3A 03 */ + "\072\004medium not present - medium auxiliary memory accessible", /* 3A 04 */ + "\073\000sequential positioning error", /* 3B 00 */ + "\073\001tape position error at beginning-of-medium", /* 3B 01 */ + "\073\002tape position error at end-of-medium", /* 3B 02 */ + "\073\003tape or electronic vertical forms unit not ready", /* 3B 03 */ + "\073\004slew failure", /* 3B 04 */ + "\073\005paper jam", /* 3B 05 */ + "\073\006failed to sense top-of-form", /* 3B 06 */ + "\073\007failed to sense bottom-of-form", /* 3B 07 */ + "\073\010reposition error", /* 3B 08 */ + "\073\011read past end of medium", /* 3B 09 */ + "\073\012read past beginning of medium", /* 3B 0A */ + "\073\013position past end of medium", /* 3B 0B */ + "\073\014position past beginning of medium", /* 3B 0C */ + "\073\015medium destination element full", /* 3B 0D */ + "\073\016medium source element empty", /* 3B 0E */ + "\073\017end of medium reached", /* 3B 0F */ + "\073\021medium magazine not accessible", /* 3B 11 */ + "\073\022medium magazine removed", /* 3B 12 */ + "\073\023medium magazine inserted", /* 3B 13 */ + "\073\024medium magazine locked", /* 3B 14 */ + "\073\025medium magazine unlocked", /* 3B 15 */ + "\073\026mechanical positioning or changer error", /* 3B 16 */ +#ifdef __used__ + "\074\000", /* 3C 00 */ +#endif + "\075\000invalid bits in identify message", /* 3D 00 */ + "\076\000logical unit has not self-configured yet", /* 3E 00 */ + "\076\001logical unit failure", /* 3E 01 */ + "\076\002timeout on logical unit", /* 3E 02 */ + "\076\003logical unit failed self-test", /* 3E 03 */ + "\076\004logical unit unable to update self-test log", /* 3E 04 */ + "\077\000target operating conditions have changed", /* 3F 00 */ + "\077\001microcode has been changed", /* 3F 01 */ + "\077\002changed operating definition", /* 3F 02 */ + "\077\003inquiry data has changed", /* 3F 03 */ + "\077\004component device attached", /* 3F 04 */ + "\077\005device identifier changed", /* 3F 05 */ + "\077\006redundancy group created or modified", /* 3F 06 */ + "\077\007redundancy group deleted", /* 3F 07 */ + "\077\010spare created or modified", /* 3F 08 */ + "\077\011spare deleted", /* 3F 09 */ + "\077\012volume set created or modified", /* 3F 0A */ + "\077\013volume set deleted", /* 3F 0B */ + "\077\014volume set deassigned", /* 3F 0C */ + "\077\015volume set reassigned", /* 3F 0D */ + "\077\016reported luns data has changed", /* 3F 0E */ + "\077\017echo buffer overwritten", /* 3F 0F */ + "\077\020medium loadable", /* 3F 10 */ + "\077\021medium auxiliary memory accessible", /* 3F 11 */ + "\100\000ram failure (should use 40 nn)", /* 40 00 */ +#ifdef XXX + "\100\000nn diagnostic failure on component nn (80h-ffh)", /* 40 00 */ +#endif + "\100\000diagnostic failure on component nn (80h-ffh)", /* 40 00 */ + "\101\000data path failure (should use 40 nn)", /* 41 00 */ + "\102\000power-on or self-test failure (should use 40 nn)", /* 42 00 */ + "\103\000message error", /* 43 00 */ + "\104\000internal target failure", /* 44 00 */ + "\105\000select or reselect failure", /* 45 00 */ + "\106\000unsuccessful soft reset", /* 46 00 */ + "\107\000scsi parity error", /* 47 00 */ + "\107\001data phase crc error detected", /* 47 01 */ + "\107\002scsi parity error detected during st data phase", /* 47 02 */ + "\107\003information unit crc error detected", /* 47 03 */ + "\107\004asynchronous information protection error detected", /* 47 04 */ + "\110\000initiator detected error message received", /* 48 00 */ + "\111\000invalid message error", /* 49 00 */ + "\112\000command phase error", /* 4A 00 */ + "\113\000data phase error", /* 4B 00 */ + "\114\000logical unit failed self-configuration", /* 4C 00 */ +#ifdef XXX + "\115\000nn tagged overlapped commands (nn = queue tag)", /* 4D 00 */ +#endif + "\115\000tagged overlapped commands (nn = queue tag)", /* 4D 00 */ + "\116\000overlapped commands attempted", /* 4E 00 */ +#ifdef __used__ + "\117\000", /* 4F 00 */ +#endif + "\120\000write append error", /* 50 00 */ + "\120\001write append position error", /* 50 01 */ + "\120\002position error related to timing", /* 50 02 */ + "\121\000erase failure", /* 51 00 */ + "\121\001erase failure - incomplete erase operation detected", /* 51 01 */ + "\122\000cartridge fault", /* 52 00 */ + "\123\000media load or eject failed", /* 53 00 */ + "\123\001unload tape failure", /* 53 01 */ + "\123\002medium removal prevented", /* 53 02 */ + "\124\000scsi to host system interface failure", /* 54 00 */ + "\125\000system resource failure", /* 55 00 */ + "\125\001system buffer full", /* 55 01 */ + "\125\002insufficient reservation resources", /* 55 02 */ + "\125\003insufficient resources", /* 55 03 */ + "\125\004insufficient registration resources", /* 55 04 */ + "\125\005access controls code 4 (99-314) [proposed]", /* 55 05 */ + "\125\006auxiliary memory code 1 (99-148) [proposed]", /* 55 06 */ +#ifdef __used__ + "\126\000", /* 56 00 */ +#endif + "\127\000unable to recover table-of-contents", /* 57 00 */ + "\130\000generation does not exist", /* 58 00 */ + "\131\000updated block read", /* 59 00 */ + "\132\000operator request or state change input", /* 5A 00 */ + "\132\001operator medium removal request", /* 5A 01 */ + "\132\002operator selected write protect", /* 5A 02 */ + "\132\003operator selected write permit", /* 5A 03 */ + "\133\000log exception", /* 5B 00 */ + "\133\001threshold condition met", /* 5B 01 */ + "\133\002log counter at maximum", /* 5B 02 */ + "\133\003log list codes exhausted", /* 5B 03 */ + "\134\000rpl status change", /* 5C 00 */ + "\134\001spindles synchronized", /* 5C 01 */ + "\134\002spindles not synchronized", /* 5C 02 */ + "\135\000failure prediction threshold exceeded", /* 5D 00 */ + "\135\001media failure prediction threshold exceeded", /* 5D 01 */ + "\135\002logical unit failure prediction threshold exceeded", /* 5D 02 */ + "\135\003spare area exhaustion prediction threshold exceeded", /* 5D 03 */ + "\135\020hardware impending failure general hard drive failure",/* 5D 10 */ + "\135\021hardware impending failure drive error rate too high", /* 5D 11 */ + "\135\022hardware impending failure data error rate too high", /* 5D 12 */ + "\135\023hardware impending failure seek error rate too high", /* 5D 13 */ + "\135\024hardware impending failure too many block reassigns", /* 5D 14 */ + "\135\025hardware impending failure access times too high", /* 5D 15 */ + "\135\026hardware impending failure start unit times too high", /* 5D 16 */ + "\135\027hardware impending failure channel parametrics",/* 5D 17 */ + "\135\030hardware impending failure controller detected",/* 5D 18 */ + "\135\031hardware impending failure throughput performance", /* 5D 19 */ + "\135\032hardware impending failure seek time performance", /* 5D 1A */ + "\135\033hardware impending failure spin-up retry count", /* 5D 1B */ + "\135\034hardware impending failure drive calibration retry count", /* 5D 1C */ + "\135\040controller impending failure general hard drive failure", /* 5D 20 */ + "\135\041controller impending failure drive error rate too high", /* 5D 21 */ + "\135\042controller impending failure data error rate too high",/* 5D 22 */ + "\135\043controller impending failure seek error rate too high",/* 5D 23 */ + "\135\044controller impending failure too many block reassigns",/* 5D 24 */ + "\135\045controller impending failure access times too high", /* 5D 25 */ + "\135\046controller impending failure start unit times too high", /* 5D 26 */ + "\135\047controller impending failure channel parametrics", /* 5D 27 */ + "\135\050controller impending failure controller detected", /* 5D 28 */ + "\135\051controller impending failure throughput performance", /* 5D 29 */ + "\135\052controller impending failure seek time performance", /* 5D 2A */ + "\135\053controller impending failure spin-up retry count", /* 5D 2B */ + "\135\054controller impending failure drive calibration retry count", /* 5D 2C */ + "\135\060data channel impending failure general hard drive failure", /* 5D 30 */ + "\135\061data channel impending failure drive error rate too high", /* 5D 31 */ + "\135\062data channel impending failure data error rate too high", /* 5D 32 */ + "\135\063data channel impending failure seek error rate too high", /* 5D 33 */ + "\135\064data channel impending failure too many block reassigns", /* 5D 34 */ + "\135\065data channel impending failure access times too high", /* 5D 35 */ + "\135\066data channel impending failure start unit times too high", /* 5D 36 */ + "\135\067data channel impending failure channel parametrics", /* 5D 37 */ + "\135\070data channel impending failure controller detected", /* 5D 38 */ + "\135\071data channel impending failure throughput performance",/* 5D 39 */ + "\135\072data channel impending failure seek time performance", /* 5D 3A */ + "\135\073data channel impending failure spin-up retry count", /* 5D 3B */ + "\135\074data channel impending failure drive calibration retry count", /* 5D 3C */ + "\135\100servo impending failure general hard drive failure", /* 5D 40 */ + "\135\101servo impending failure drive error rate too high", /* 5D 41 */ + "\135\102servo impending failure data error rate too high", /* 5D 42 */ + "\135\103servo impending failure seek error rate too high", /* 5D 43 */ + "\135\104servo impending failure too many block reassigns", /* 5D 44 */ + "\135\105servo impending failure access times too high",/* 5D 45 */ + "\135\106servo impending failure start unit times too high", /* 5D 46 */ + "\135\107servo impending failure channel parametrics", /* 5D 47 */ + "\135\110servo impending failure controller detected", /* 5D 48 */ + "\135\111servo impending failure throughput performance", /* 5D 49 */ + "\135\112servo impending failure seek time performance",/* 5D 4A */ + "\135\113servo impending failure spin-up retry count", /* 5D 4B */ + "\135\114servo impending failure drive calibration retry count",/* 5D 4C */ + "\135\120spindle impending failure general hard drive failure", /* 5D 50 */ + "\135\121spindle impending failure drive error rate too high", /* 5D 51 */ + "\135\122spindle impending failure data error rate too high", /* 5D 52 */ + "\135\123spindle impending failure seek error rate too high", /* 5D 53 */ + "\135\124spindle impending failure too many block reassigns", /* 5D 54 */ + "\135\125spindle impending failure access times too high", /* 5D 55 */ + "\135\126spindle impending failure start unit times too high", /* 5D 56 */ + "\135\127spindle impending failure channel parametrics",/* 5D 57 */ + "\135\130spindle impending failure controller detected",/* 5D 58 */ + "\135\131spindle impending failure throughput performance", /* 5D 59 */ + "\135\132spindle impending failure seek time performance", /* 5D 5A */ + "\135\133spindle impending failure spin-up retry count",/* 5D 5B */ + "\135\134spindle impending failure drive calibration retry count", /* 5D 5C */ + "\135\140firmware impending failure general hard drive failure",/* 5D 60 */ + "\135\141firmware impending failure drive error rate too high", /* 5D 61 */ + "\135\142firmware impending failure data error rate too high", /* 5D 62 */ + "\135\143firmware impending failure seek error rate too high", /* 5D 63 */ + "\135\144firmware impending failure too many block reassigns", /* 5D 64 */ + "\135\145firmware impending failure access times too high", /* 5D 65 */ + "\135\146firmware impending failure start unit times too high", /* 5D 66 */ + "\135\147firmware impending failure channel parametrics", /* 5D 67 */ + "\135\150firmware impending failure controller detected", /* 5D 68 */ + "\135\151firmware impending failure throughput performance", /* 5D 69 */ + "\135\152firmware impending failure seek time performance", /* 5D 6A */ + "\135\153firmware impending failure spin-up retry count", /* 5D 6B */ + "\135\154firmware impending failure drive calibration retry count", /* 5D 6C */ + "\135\377failure prediction threshold exceeded (false)",/* 5D FF */ + "\136\000low power condition on", /* 5E 00 */ + "\136\001idle condition activated by timer", /* 5E 01 */ + "\136\002standby condition activated by timer", /* 5E 02 */ + "\136\003idle condition activated by command", /* 5E 03 */ + "\136\004standby condition activated by command", /* 5E 04 */ + "\136\101power state change to active", /* 5E 41 */ + "\136\102power state change to idle", /* 5E 42 */ + "\136\103power state change to standby", /* 5E 43 */ + "\136\105power state change to sleep", /* 5E 45 */ + "\136\107power state change to device control", /* 5E 47 */ +#ifdef __used__ + "\137\000", /* 5F 00 */ +#endif + "\140\000lamp failure", /* 60 00 */ + "\141\000video acquisition error", /* 61 00 */ + "\141\001unable to acquire video", /* 61 01 */ + "\141\002out of focus", /* 61 02 */ + "\142\000scan head positioning error", /* 62 00 */ + "\143\000end of user area encountered on this track", /* 63 00 */ + "\143\001packet does not fit in available space", /* 63 01 */ + "\144\000illegal mode for this track", /* 64 00 */ + "\144\001invalid packet size", /* 64 01 */ + "\145\000voltage fault", /* 65 00 */ + "\146\000automatic document feeder cover up", /* 66 00 */ + "\146\001automatic document feeder lift up", /* 66 01 */ + "\146\002document jam in automatic document feeder", /* 66 02 */ + "\146\003document miss feed automatic in document feeder", /* 66 03 */ + "\147\000configuration failure", /* 67 00 */ + "\147\001configuration of incapable logical units failed", /* 67 01 */ + "\147\002add logical unit failed", /* 67 02 */ + "\147\003modification of logical unit failed", /* 67 03 */ + "\147\004exchange of logical unit failed", /* 67 04 */ + "\147\005remove of logical unit failed", /* 67 05 */ + "\147\006attachment of logical unit failed", /* 67 06 */ + "\147\007creation of logical unit failed", /* 67 07 */ + "\147\010assign failure occurred", /* 67 08 */ + "\147\011multiply assigned logical unit", /* 67 09 */ + "\147\012asymmetric access code 4 (00-232) [proposed]", /* 67 0A */ + "\147\013asymmetric access code 5 (00-232) [proposed]", /* 67 0B */ + "\150\000logical unit not configured", /* 68 00 */ + "\151\000data loss on logical unit", /* 69 00 */ + "\151\001multiple logical unit failures", /* 69 01 */ + "\151\002parity/data mismatch", /* 69 02 */ + "\152\000informational, refer to log", /* 6A 00 */ + "\153\000state change has occurred", /* 6B 00 */ + "\153\001redundancy level got better", /* 6B 01 */ + "\153\002redundancy level got worse", /* 6B 02 */ + "\154\000rebuild failure occurred", /* 6C 00 */ + "\155\000recalculate failure occurred", /* 6D 00 */ + "\156\000command to logical unit failed", /* 6E 00 */ + "\157\000copy protection key exchange failure - authentication failure",/* 6F 00 */ + "\157\001copy protection key exchange failure - key not present", /* 6F 01 */ + "\157\002copy protection key exchange failure - key not established", /* 6F 02 */ + "\157\003read of scrambled sector without authentication", /* 6F 03 */ + "\157\004media region code is mismatched to logical unit region", /* 6F 04 */ + "\157\005drive region must be permanent/region reset count error", /* 6F 05 */ +#ifdef XXX + "\160\000nn decompression exception short algorithm id of nn", /* 70 00 */ +#endif + "\160\000decompression exception short algorithm id of nn", /* 70 00 */ + "\161\000decompression exception long algorithm id", /* 71 00 */ + "\162\000session fixation error", /* 72 00 */ + "\162\001session fixation error writing lead-in", /* 72 01 */ + "\162\002session fixation error writing lead-out", /* 72 02 */ + "\162\003session fixation error - incomplete track in session", /* 72 03 */ + "\162\004empty or partially written reserved track", /* 72 04 */ + "\162\005no more track reservations allowed", /* 72 05 */ + "\163\000cd control error", /* 73 00 */ + "\163\001power calibration area almost full", /* 73 01 */ + "\163\002power calibration area is full", /* 73 02 */ + "\163\003power calibration area error", /* 73 03 */ + "\163\004program memory area update failure", /* 73 04 */ + "\163\005program memory area is full", /* 73 05 */ + "\163\006rma/pma is almost full", /* 73 06 */ +#ifdef __used__ + "\164\000", /* 74 00 */ + "\165\000", /* 75 00 */ + "\166\000", /* 76 00 */ + "\167\000", /* 77 00 */ + "\170\000", /* 78 00 */ + "\171\000", /* 79 00 */ + "\172\000", /* 7A 00 */ + "\173\000", /* 7B 00 */ + "\174\000", /* 7C 00 */ + "\175\000", /* 7D 00 */ + "\176\000", /* 7E 00 */ + "\177\000", /* 7F 00 */ +#endif +#ifdef XXX + "\200\000start vendor unique", /* 80 00 */ +#endif + NULL +}; + +#ifdef SMO_C501 +static const char *sd_smo_c501_error_str[] = { + "\012\000disk not inserted", /* 0x0a */ + "\013\000load/unload failure", /* 0x0b */ + "\014\000spindle failure", /* 0x0c */ + "\015\000focus failure", /* 0x0d */ + "\016\000tracking failure", /* 0x0e */ + "\017\000bias magnet failure", /* 0x0f */ + "\043\000illegal function for medium type", /* 0x23 */ +/*XXX*/ "\070\000recoverable write error", /* 0x38 */ +/*XXX*/ "\071\000write error recovery failed", /* 0x39 */ + "\072\000defect list update failed", /* 0x3a */ + "\075\000defect list not available", /* 0x3d */ + "\200\000limited laser life", /* 0x80 */ + "\201\000laser focus coil over-current", /* 0x81 */ + "\202\000laser tracking coil over-current", /* 0x82 */ + "\203\000temperature alarm", /* 0x83 */ + NULL +}; +#endif + +static char *sd_sense_keys[] = { + "No Additional Sense", /* 0x00 */ + "Recovered Error", /* 0x01 */ + "Not Ready", /* 0x02 */ + "Medium Error", /* 0x03 */ + "Hardware Error", /* 0x04 */ + "Illegal Request", /* 0x05 */ + "Unit Attention", /* 0x06 */ + "Data Protect", /* 0x07 */ + "Blank Check", /* 0x08 */ + "Vendor Unique", /* 0x09 */ + "Copy Aborted", /* 0x0a */ + "Aborted Command", /* 0x0b */ + "Equal", /* 0x0c */ + "Volume Overflow", /* 0x0d */ + "Miscompare", /* 0x0e */ + "Reserved" /* 0x0f */ +}; + +#if 0 +static char *sd_cmds[] = { + "\000test unit ready", /* 0x00 */ + "\001rezero", /* 0x01 */ + "\003request sense", /* 0x03 */ + "\004format", /* 0x04 */ + "\007reassign", /* 0x07 */ + "\010read", /* 0x08 */ + "\012write", /* 0x0a */ + "\013seek", /* 0x0b */ + "\022inquiry", /* 0x12 */ + "\025mode select", /* 0x15 */ + "\026reserve", /* 0x16 */ + "\027release", /* 0x17 */ + "\030copy", /* 0x18 */ + "\032mode sense", /* 0x1a */ + "\033start/stop", /* 0x1b */ + "\036door lock", /* 0x1e */ + "\067read defect data", /* 0x37 */ + NULL +}; +#endif + + +const char * +usal_sensemsg(register int ctype, register int code, register int qual, + register const char **vec, char *sbuf, int maxcnt) +{ + register int i; + + /* + * Ignore controller type if error vec is supplied. + */ + if (vec == (const char **)NULL) switch (ctype) { + case DEV_MD21: + vec = sd_ccs_error_str; + break; + + case DEV_ACB40X0: + case DEV_ACB4000: + case DEV_ACB4010: + case DEV_ACB4070: + case DEV_ACB5500: + vec = sd_adaptec_error_str; + break; + +#ifdef SMO_C501 + case DEV_SONY_SMO: + vec = sd_smo_c501_error_str; + break; +#endif + + default: + vec = sd_ccs_error_str; + } + if (vec == (const char **)NULL) + return (""); + + for (i = 0; i < 2; i++) { + while (*vec != (char *) NULL) { + if (code == (Uchar)(*vec)[0] && + qual == (Uchar)(*vec)[1]) { + return (&(*vec)[2]); + } else { + vec++; /* Next entry */ + } + } + if (*vec == (char *) NULL) /* End of List: switch over */ + vec = sd_ccs_error_str; + } + if (code == 0x40) { + snprintf(sbuf, maxcnt, + "diagnostic failure on component 0x%X", qual); + return (sbuf); + } + if (code == 0x4D) { + snprintf(sbuf, maxcnt, + "tagged overlapped commands, queue tag is 0x%X", + qual); + return (sbuf); + } + if (code == 0x70) { + snprintf(sbuf, maxcnt, + "decompression exception short algorithm id of 0x%X", + qual); + return (sbuf); + } + if (qual != 0) + return ((char *)NULL); + + if (code < 0x80) { + snprintf(sbuf, maxcnt, "invalid sense code 0x%X", code); + return (sbuf); + } + snprintf(sbuf, maxcnt, "vendor unique sense code 0x%X", code); + return (sbuf); +} + +#undef sense /*XXX JS Hack, solange usalio.h noch nicht fertig ist */ +int +usal__errmsg(SCSI *usalp, char *obuf, int maxcnt, + register struct scsi_sense *sense, + register struct scsi_status *status, int sense_code) +{ + char sbuf[80]; + const char *sensemsg, *cmdname, *sensekey; +#define ext_sense ((struct scsi_ext_sense* ) sense) + register int blkno = 0; + register int code; + int badqual = 0; + int qual = 0; + int fru = 0; + int key = 0; + int segment = 0; + int blkvalid = 0; + int fm = 0; + int eom = 0; + int ili = 0; + int sksv = 0; + int n; + int sizeleft = maxcnt; + + sensekey = sensemsg = "[]"; + if (sense->code >= 0x70) { + if (sense_code >= 0) + code = sense_code; + else + code = ext_sense->sense_code; + segment = ext_sense->seg_num; + qual = ext_sense->qual_code; + fru = ext_sense->fru_code; + sksv = ext_sense->sksv; + } else { + code = sense->code; + } + if (status->chk == 0) { + sensemsg = "no sense"; + } else { + if (sense->code >= 0x70) { + key = ext_sense->key; + if (key < 0x10) + sensekey = sd_sense_keys[ext_sense->key]; + else + sensekey = "invalid sensekey"; + blkno = (ext_sense->info_1 << 24) | + (ext_sense->info_2 << 16) | + (ext_sense->info_3 << 8) | + ext_sense->info_4; + fm = ext_sense->fil_mk; + eom = ext_sense->eom; + ili = ext_sense->ili; + } else { + key = -1; + sensekey = "[]"; + blkno = (sense->high_addr << 16) | + (sense->mid_addr << 8) | + sense->low_addr; + fm = eom = 0; + } + blkvalid = sense->adr_val; + + sensemsg = usal_sensemsg(usalp->dev, code, qual, usalp->nonstderrs, sbuf, sizeof(sbuf)); + if (sensemsg == NULL) { + sensemsg = usal_sensemsg(usalp->dev, code, 0, usalp->nonstderrs, sbuf, sizeof(sbuf)); + badqual = 1; + } + } +/* + if (un->un_cmd < sizeof(scsi_cmds)) { + cmdname = scsi_cmds[un->un_cmd]; + } else { + cmdname = "unknown cmd"; + } +*/ + cmdname = ""; + n = snprintf(obuf, sizeleft, "%sSense Key: 0x%X %s%s, Segment %d\n", + cmdname, key, sensekey, + (sense->code == 0x71)?", deferred error":"", + segment); + if (n <= 0) { + obuf[0] = '\0'; + return (maxcnt - sizeleft); + } + obuf += n; + sizeleft -= n; + n = snprintf(obuf, sizeleft, "Sense Code: 0x%02X Qual 0x%02X %s%s%s%s Fru 0x%X\n", + code, qual, *sensemsg?"(":"", sensemsg, *sensemsg?")":"", + badqual? " [No matching qualifier]":"", + fru); + if (n <= 0) { + obuf[0] = '\0'; + return (maxcnt - sizeleft); + } + obuf += n; + sizeleft -= n; + n = snprintf(obuf, sizeleft, "Sense flags: Blk %d %s%s%s%s", + blkno, blkvalid?"(valid) ":"(not valid) ", + fm?"file mark detected ":"", + eom?"end of medium ":"", + ili?"illegal block length ":""); + if (n <= 0) { + obuf[0] = '\0'; + return (maxcnt - sizeleft); + } + obuf += n; + sizeleft -= n; + if (!sksv) { + n = snprintf(obuf, sizeleft, "\n"); + if (n <= 0) { + obuf[0] = '\0'; + return (maxcnt - sizeleft); + } + obuf += n; + sizeleft -= n; + return (maxcnt - sizeleft); + } + switch (key) { + + case SC_ILLEGAL_REQUEST: + n = snprintf(obuf, sizeleft, "error refers to %s part, bit ptr %d %s field ptr %d", + ext_sense->cd? "command":"data", + (int)ext_sense->bptr, + ext_sense->bpv? "(valid)":"(not valid)", + ext_sense->field_ptr[0] << 8 | + ext_sense->field_ptr[1]); + if (n <= 0) { + obuf[0] = '\0'; + return (maxcnt - sizeleft); + } + obuf += n; + sizeleft -= n; + break; + + case SC_RECOVERABLE_ERROR: + case SC_HARDWARE_ERROR: + case SC_MEDIUM_ERROR: + n = snprintf(obuf, sizeleft, "actual retry count %d", + ext_sense->field_ptr[0] << 8 | + ext_sense->field_ptr[1]); + if (n <= 0) { + obuf[0] = '\0'; + return (maxcnt - sizeleft); + } + obuf += n; + sizeleft -= n; + break; + + case SC_NOT_READY: + n = snprintf(obuf, sizeleft, "operation %d%% done", + (100*(ext_sense->field_ptr[0] << 8 | + ext_sense->field_ptr[1]))/(unsigned)65536); + if (n < 0) { + obuf[0] = '\0'; + return (maxcnt - sizeleft); + } + obuf += n; + sizeleft -= n; + break; + } + n = snprintf(obuf, sizeleft, "\n"); + if (n <= 0) { + obuf[0] = '\0'; + return (maxcnt - sizeleft); + } + obuf += n; + sizeleft -= n; + return (maxcnt - sizeleft); +} + +#ifdef DEBUG +print_err(code, ctype) +{ + register int i; + register char **vec = (char **)NULL; + + switch (ctype) { + case CTYPE_MD21: + case CTYPE_CCS: + vec = sd_ccs_error_str; + break; + + case CTYPE_ACB4000: + vec = sd_adaptec_error_str; + break; + +#ifdef SMO_C501 + case CTYPE_SMO_C501: + vec = sd_smo_c501_error_str; + break; +#endif + +#ifdef CDD_521 + case DEV_CDD_521: + vec = sd_cdd_521_error_str; + break; +#endif + } + printf("error code: 0x%x", code); + if (vec == (char **)NULL) + return; + + for (i = 0; i < 2; i++) { + while (*vec != (char *) NULL) { + if (code == (Uchar)*vec[0]) { + printf(" (%s)", (char *)((int)(*vec)+1)); + return; + } else + vec++; + } + if (*vec == (char *) NULL) + vec = sd_ccs_error_str; + } +} + + +int main(int argc, char *argv[]) +{ + int i; + +#ifdef ACB + for (i = 0; i < 0x30; i++) { +/* printf("Code: 0x%x Key: 0x%x ", i, sd_adaptec_keys[i]);*/ + printf("Key: 0x%x %-16s ", sd_adaptec_keys[i], + sd_sense_keys[sd_adaptec_keys[i]] ); + js_print_err(i, CTYPE_ACB4000); + printf("\n"); + } +#else +/* for (i = 0; i < 0x84; i++) {*/ + for (i = 0; i < 0xd8; i++) { +/* print_err(i, CTYPE_SMO_C501);*/ + print_err(i, DEV_CDD_521); + printf("\n"); + } +#endif +} +#endif diff --git a/libusal/scsihack.c b/libusal/scsihack.c new file mode 100644 index 0000000..5427ad0 --- /dev/null +++ b/libusal/scsihack.c @@ -0,0 +1,483 @@ +/* + * 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. + * + */ + +/* @(#)scsihack.c 1.44 06/01/30 Copyright 1997,2000,2001 J. Schilling */ +/* + * Interface for other generic SCSI implementations. + * Emulate the functionality of /dev/usal? with the local + * SCSI user land implementation. + * + * To add a new hack, add something like: + * + * #ifdef __FreeBSD__ + * #define SCSI_IMPL + * #include some code + * #endif + * + * Warning: you may change this source or add new SCSI tranport + * implementations, but if you do that you need to change the + * _usal_version and _usal_auth* string that are returned by the + * SCSI transport code. + * Choose your name instead of "schily" and make clear that the version + * string is related to a modified source. + * If your version has been integrated into the main steam release, + * the return value will be set to "schily". + * + * Copyright (c) 1997,2000,2001 J. Schilling + */ +/* + * 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. + */ + +#include <mconfig.h> + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> /* Include various defs needed with some OS */ +#endif +#include <stdio.h> +#include <standard.h> +#include <stdxlib.h> +#include <unixstd.h> +#include <errno.h> +#include <timedefs.h> +#include <sys/ioctl.h> +#include <fctldefs.h> +#include <strdefs.h> +#include <schily.h> + +#include <usal/usalcmd.h> +#include <usal/scsitransp.h> +#include "usaltimes.h" + +#ifndef HAVE_ERRNO_DEF +extern int errno; +#endif + +static int usalo_send(SCSI *usalp); +static char *usalo_version(SCSI *usalp, int what); +static int usalo_help(SCSI *usalp, FILE *f); +static int usalo_open(SCSI *usalp, char *device); +static int usalo_close(SCSI *usalp); +static long usalo_maxdma(SCSI *usalp, long amt); +static void *usalo_getbuf(SCSI *usalp, long amt); +static void usalo_freebuf(SCSI *usalp); + +static BOOL usalo_havebus(SCSI *usalp, int busno); +static int usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun); +static char * usalo_natname(SCSI *usalp, int busno, int tgt, int tlun); +static int usalo_initiator_id(SCSI *usalp); +static int usalo_isatapi(SCSI *usalp); +static int usalo_reset(SCSI *usalp, int what); + +static char _usal_auth_cdrkit[] = "cdrkit-team"; /* The author for this module */ + +usal_ops_t usal_std_ops = { + usalo_send, + usalo_version, + usalo_help, + usalo_open, + usalo_close, + usalo_maxdma, + usalo_getbuf, + usalo_freebuf, + usalo_havebus, + usalo_fileno, + usalo_initiator_id, + usalo_isatapi, + usalo_reset, + usalo_natname, +}; + +/*#undef sun*/ +/*#undef __sun*/ +/*#undef __sun__*/ + +#if defined(sun) || defined(__sun) || defined(__sun__) +#define SCSI_IMPL /* We have a SCSI implementation for Sun */ + +#include "scsi-sun.c" + +#endif /* Sun */ + + +#ifdef linux +#define SCSI_IMPL /* We have a SCSI implementation for Linux */ + +#ifdef not_needed /* We now have a local vrersion of pg.h */ +#ifndef HAVE_LINUX_PG_H /* If we are compiling on an old version */ +# undef USE_PG_ONLY /* there is no 'pg' driver and we cannot */ +# undef USE_PG /* include <linux/pg.h> which is needed */ +#endif /* by the pg transport code. */ +#endif + +#ifdef USE_PG_ONLY +#include "scsi-linux-pg.c" +#else +#include "scsi-linux-sg.c" +#endif + +#endif /* linux */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) +#define SCSI_IMPL /* We have a SCSI implementation for *BSD */ + +#include "scsi-bsd.c" + +#endif /* *BSD */ + +#if defined(__bsdi__) /* We have a SCSI implementation for BSD/OS 3.x (and later?) */ +# include <sys/param.h> +# if (_BSDI_VERSION >= 199701) +# define SCSI_IMPL + +# include "scsi-bsd-os.c" + +# endif /* BSD/OS >= 3.0 */ +#endif /* BSD/OS */ + +#ifdef __sgi +#define SCSI_IMPL /* We have a SCSI implementation for SGI */ + +#include "scsi-sgi.c" + +#endif /* SGI */ + +#ifdef __hpux +#define SCSI_IMPL /* We have a SCSI implementation for HP-UX */ + +#include "scsi-hpux.c" + +#endif /* HP-UX */ + +#if defined(_IBMR2) || defined(_AIX) +#define SCSI_IMPL /* We have a SCSI implementation for AIX */ + +#include "scsi-aix.c" + +#endif /* AIX */ + +#if defined(__NeXT__) || defined(IS_MACOS_X) +#if defined(HAVE_BSD_DEV_SCSIREG_H) +/* + * This is the + */ +#define SCSI_IMPL /* We found a SCSI implementation for NextStep and Mac OS X */ + +#include "scsi-next.c" +#else + +#define SCSI_IMPL /* We found a SCSI implementation for Mac OS X (Darwin-1.4) */ + +#include "scsi-mac-iokit.c" + +#endif /* HAVE_BSD_DEV_SCSIREG_H */ + +#endif /* NEXT / Mac OS X */ + +#if defined(__osf__) +#define SCSI_IMPL /* We have a SCSI implementation for OSF/1 */ + +#include "scsi-osf.c" + +#endif /* OSF/1 */ + +#ifdef VMS +#define SCSI_IMPL /* We have a SCSI implementation for VMS */ + +#include "scsi-vms.c" + +#endif /* VMS */ + +#ifdef OPENSERVER +#define SCSI_IMPL /* We have a SCSI implementation for SCO OpenServer */ + +#include "scsi-openserver.c" + +#endif /* SCO */ + +#ifdef UNIXWARE +#define SCSI_IMPL /* We have a SCSI implementation for SCO UnixWare */ + +#include "scsi-unixware.c" + +#endif /* UNIXWARE */ + +#ifdef __OS2 +#define SCSI_IMPL /* We have a SCSI implementation for OS/2 */ + +#include "scsi-os2.c" + +#endif /* OS/2 */ + +#ifdef __BEOS__ +#define SCSI_IMPL /* Yep, BeOS does that funky scsi stuff */ +#include "scsi-beos.c" +#endif + +#ifdef __CYGWIN32__ +#define SCSI_IMPL /* Yep, we support WNT and W9? */ +#include "scsi-wnt.c" +#endif + +#ifdef apollo +#define SCSI_IMPL /* We have a SCSI implementation for Apollo Domain/OS */ +#include "scsi-apollo.c" +#endif + +#ifdef AMIGA /* We have a SCSI implementation for AmigaOS */ +#define SCSI_IMPL +#include "scsi-amigaos.c" +#endif + +#if defined(__QNXNTO__) || defined(__QNX__) +#define SCSI_IMPL /* We have a SCSI implementation for QNX */ +#include "scsi-qnx.c" +#endif /* QNX */ + +#ifdef __DJGPP__ /* We have a SCSI implementation for MS-DOS/DJGPP */ +#define SCSI_IMPL +#include "scsi-dos.c" +#endif + +#ifdef __NEW_ARCHITECTURE +#define SCSI_IMPL /* We have a SCSI implementation for XXX */ +/* + * Add new hacks here + */ +#include "scsi-new-arch.c" +#endif + + +#ifndef SCSI_IMPL +/* + * To make scsihack.c compile on all architectures. + * This does not mean that you may use it, but you can see + * if other problems exist. + */ +#define usalo_dversion usalo_version +#define usalo_dhelp usalo_help +#define usalo_dopen usalo_open +#define usalo_dclose usalo_close +#define usalo_dmaxdma usalo_maxdma +#define usalo_dgetbuf usalo_getbuf +#define usalo_dfreebuf usalo_freebuf +#define usalo_dhavebus usalo_havebus +#define usalo_dfileno usalo_fileno +#define usalo_dinitiator_id usalo_initiator_id +#define usalo_disatapi usalo_isatapi +#define usalo_dreset usalo_reset +#define usalo_dsend usalo_send +#endif /* SCSI_IMPL */ + +static int usalo_dsend(SCSI *usalp); +static char *usalo_dversion(SCSI *usalp, int what); +static int usalo_dhelp(SCSI *usalp, FILE *f); +static int usalo_nohelp(SCSI *usalp, FILE *f); +static int usalo_ropen(SCSI *usalp, char *device); +static int usalo_dopen(SCSI *usalp, char *device); +static int usalo_dclose(SCSI *usalp); +static long usalo_dmaxdma(SCSI *usalp, long amt); +static void *usalo_dgetbuf(SCSI *usalp, long amt); +static void usalo_dfreebuf(SCSI *usalp); +static BOOL usalo_dhavebus(SCSI *usalp, int busno); +static int usalo_dfileno(SCSI *usalp, int busno, int tgt, int tlun); +static int usalo_dinitiator_id(SCSI *usalp); +static int usalo_disatapi(SCSI *usalp); +static int usalo_dreset(SCSI *usalp, int what); + +usal_ops_t usal_remote_ops = { + usalo_dsend, + usalo_dversion, + usalo_nohelp, + usalo_ropen, + usalo_dclose, + usalo_dmaxdma, + usalo_dgetbuf, + usalo_dfreebuf, + usalo_dhavebus, + usalo_dfileno, + usalo_dinitiator_id, + usalo_disatapi, + usalo_dreset, + usalo_natname, +}; + +usal_ops_t usal_dummy_ops = { + usalo_dsend, + usalo_dversion, + usalo_dhelp, + usalo_dopen, + usalo_dclose, + usalo_dmaxdma, + usalo_dgetbuf, + usalo_dfreebuf, + usalo_dhavebus, + usalo_dfileno, + usalo_dinitiator_id, + usalo_disatapi, + usalo_dreset, + usalo_natname, +}; + +/* + * 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_dversion[] = "scsihack.c-1.44"; /* The version for this transport*/ + +/* + * 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_dversion(SCSI *usalp, int what) +{ + if (usalp != (SCSI *)0) { + switch (what) { + + case SCG_VERSION: + return (_usal_trans_dversion); + /* + * 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_dhelp(SCSI *usalp, FILE *f) +{ + printf("None.\n"); + return (0); +} + +static int +usalo_nohelp(SCSI *usalp, FILE *f) +{ + return (0); +} + +static int +usalo_ropen(SCSI *usalp, char *device) +{ + comerrno(EX_BAD, "No remote SCSI transport available.\n"); + return (-1); /* Keep lint happy */ +} + +#ifndef SCSI_IMPL +static int +usalo_dopen(SCSI *usalp, char *device) +{ + comerrno(EX_BAD, "No local SCSI transport implementation for this architecture.\n"); + return (-1); /* Keep lint happy */ +} +#else +static int +usalo_dopen(SCSI *usalp, char *device) +{ + comerrno(EX_BAD, "SCSI open usage error.\n"); + return (-1); /* Keep lint happy */ +} +#endif /* SCSI_IMPL */ + +static int +usalo_dclose(SCSI *usalp) +{ + errno = EINVAL; + return (-1); +} + +static long +usalo_dmaxdma(SCSI *usalp, long amt) +{ + errno = EINVAL; + return (0L); +} + +static void * +usalo_dgetbuf(SCSI *usalp, long amt) +{ + errno = EINVAL; + return ((void *)0); +} + +static void +usalo_dfreebuf(SCSI *usalp) +{ +} + +static BOOL +usalo_dhavebus(SCSI *usalp, int busno) +{ + return (FALSE); +} + +static int +usalo_dfileno(SCSI *usalp, int busno, int tgt, int tlun) +{ + return (-1); +} + +#ifndef HAVE_NAT_NAMES /* to be defined in included source if supported */ +static char * usalo_natname(SCSI *usalp, int busno, int tgt, int tlun) { + static char namebuf[81]; + snprintf(namebuf, 80, "%d,%d,%d", usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp)); + return namebuf; +} +#endif + +static int +usalo_dinitiator_id(SCSI *usalp) +{ + return (-1); +} + +static int +usalo_disatapi(SCSI *usalp) +{ + return (FALSE); +} + +static int +usalo_dreset(SCSI *usalp, int what) +{ + errno = EINVAL; + return (-1); +} + +static int +usalo_dsend(SCSI *usalp) +{ + errno = EINVAL; + return (-1); +} diff --git a/libusal/scsihelp.c b/libusal/scsihelp.c new file mode 100644 index 0000000..4ddebfa --- /dev/null +++ b/libusal/scsihelp.c @@ -0,0 +1,56 @@ +/* + * 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. + * + */ + +/* @(#)scsihelp.c 1.4 04/01/14 Copyright 2002 J. Schilling */ +/* + * usal Library + * Help subsystem + * + * Copyright (c) 2002 J. Schilling + */ +/* + * 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. + */ + +#include <mconfig.h> +#include <stdio.h> +#include <standard.h> +#include <schily.h> + +#include <usal/scsitransp.h> + +void __usal_help(FILE *f, char *name, char *tcomment, char *tind, char *tspec, + char *texample, BOOL mayscan, BOOL bydev); + +void +__usal_help(FILE *f, char *name, char *tcomment, char *tind, char *tspec, + char *texample, BOOL mayscan, BOOL bydev) +{ + fprintf(f, "\nTransport name: %s\n", name); + fprintf(f, "Transport descr.: %s\n", tcomment); + fprintf(f, "Transp. layer ind.: %s\n", tind); + fprintf(f, "Target specifier: %s\n", tspec); + fprintf(f, "Target example: %s\n", texample); + fprintf(f, "SCSI Bus scanning: %ssupported\n", mayscan? "":"not "); + fprintf(f, "Open via UNIX device: %ssupported\n", bydev? "":"not "); +} diff --git a/libusal/scsiopen.c b/libusal/scsiopen.c new file mode 100644 index 0000000..41dd1e9 --- /dev/null +++ b/libusal/scsiopen.c @@ -0,0 +1,464 @@ +/* + * 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. + * + */ + +/* @(#)scsiopen.c 1.95 04/01/14 Copyright 1995,2000 J. Schilling */ +/* + * SCSI command functions for cdrecord + * + * Copyright (c) 1995,2000 J. Schilling + */ +/* + * 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. + */ + +/* + * NOTICE: The Philips CDD 521 has several firmware bugs. + * One of them is not to respond to a SCSI selection + * within 200ms if the general load on the + * SCSI bus is high. To deal with this problem + * most of the SCSI commands are send with the + * SCG_CMD_RETRY flag enabled. + * + * Note that the only legal place to assign + * values to usal_scsibus() usal_target() and usal_lun() + * is usal_settarget(). + */ +#include <mconfig.h> + +#include <stdio.h> +#include <standard.h> +#include <stdxlib.h> +#include <unixstd.h> +#include <fctldefs.h> +#include <errno.h> +#include <strdefs.h> +#include <timedefs.h> + +#include <utypes.h> +#include <btorder.h> +#include <schily.h> + +#include <usal/usalcmd.h> +#include <usal/scsidefs.h> +#include <usal/scsireg.h> +#include <usal/scsitransp.h> + +#if defined(linux) || defined(__linux) || defined(__linux__) +extern BOOL check_linux_26(); +#endif + +#define strbeg(s1, s2) (strstr((s2), (s1)) == (s2)) + +extern int lverbose; + +SCSI *usal_open(char *scsidev, char *errs, int slen, int debug, int be_verbose); +int usal_help(FILE *f); +static int usal_scandev(char *devp, char *errs, int slen, int *busp, + int *tgtp, int *lunp); +int usal_close(SCSI * usalp); + +void usal_settimeout(SCSI * usalp, int timeout); + +SCSI *usal_smalloc(void); +void usal_sfree(SCSI *usalp); + +/* + * Open a SCSI device. + * + * Possible syntax is: + * + * Preferred: + * dev=target,lun / dev=scsibus,target,lun + * + * Needed on some systems: + * dev=devicename:target,lun / dev=devicename:scsibus,target,lun + * + * On systems that don't support SCSI Bus scanning this syntax helps: + * dev=devicename:@ / dev=devicename:@,lun + * or dev=devicename (undocumented) + * + * NOTE: As the 'lun' is part of the SCSI command descriptor block, it + * must always be known. If the OS cannot map it, it must be + * specified on command line. + */ +SCSI * +usal_open(char *scsidev, char *errs, int slen, int debug, int be_verbose) +{ + char devname[256]; + char *devp = NULL; + char *sdev = NULL; + int x1; + int bus = 0; + int tgt = 0; + int lun = 0; + int n = 0; + SCSI *usalp; + + if (errs) + errs[0] = '\0'; + usalp = usal_smalloc(); + if (usalp == NULL) { + if (errs) + snprintf(errs, slen, "No memory for SCSI structure"); + return ((SCSI *)0); + } + usalp->debug = debug; + usalp->overbose = be_verbose; + devname[0] = '\0'; + if (scsidev != NULL && scsidev[0] != '\0') { + sdev = scsidev; + if ((strncmp(scsidev, "HELP", 4) == 0) || + (strncmp(scsidev, "help", 4) == 0)) { + + return ((SCSI *)0); + } + if (strncmp(scsidev, "REMOTE", 6) == 0) { + /* + * REMOTE:user@host:scsidev or + * REMOTE(transp):user@host:scsidev + * e.g.: REMOTE(/usr/bin/ssh):user@host:scsidev + * + * We must send the complete device spec to the remote + * site to allow parsing on both sites. + */ + strncpy(devname, scsidev, sizeof (devname)-1); + devname[sizeof (devname)-1] = '\0'; + if (sdev[6] == '(' || sdev[6] == ':') + sdev = strchr(sdev, ':'); + else + sdev = NULL; + + if (sdev == NULL) { + /* + * This seems to be an illegal remote dev spec. + * Give it a chance with a standard parsing. + */ + sdev = scsidev; + devname[0] = '\0'; + } else { + /* + * Now try to go past user@host spec. + */ + if (sdev) + sdev = strchr(&sdev[1], ':'); + if (sdev) + sdev++; /* Device name follows ... */ + else + goto nulldevice; + } + } + if ((devp = strchr(sdev, ':')) == NULL) { + if (strchr(sdev, ',') == NULL) { + /* Notation form: 'devname' (undocumented) */ + /* Forward complete name to usal__open() */ + /* Fetch bus/tgt/lun values from OS */ + /* We may come here too with 'USCSI' */ + n = -1; + lun = -2; /* Lun must be known */ + if (devname[0] == '\0') { + strncpy(devname, scsidev, + sizeof (devname)-1); + devname[sizeof (devname)-1] = '\0'; + } + } else { + /* Basic notation form: 'bus,tgt,lun' */ + devp = sdev; + } + } else { + /* Notation form: 'devname:bus,tgt,lun'/'devname:@' */ + /* We may come here too with 'USCSI:' */ + if (devname[0] == '\0') { + /* + * Copy over the part before the ':' + */ + x1 = devp - scsidev; + if (x1 >= (int)sizeof (devname)) + x1 = sizeof (devname)-1; + strncpy(devname, scsidev, x1); + devname[x1] = '\0'; + } + devp++; + /* Check for a notation in the form 'devname:@' */ + if (devp[0] == '@') { + if (devp[1] == '\0') { + lun = -2; + } else if (devp[1] == ',') { + if (*astoi(&devp[2], &lun) != '\0') { + errno = EINVAL; + if (errs) + snprintf(errs, slen, + "Invalid lun specifier '%s'", + &devp[2]); + return ((SCSI *)0); + } + } + n = -1; + /* + * Got device:@ or device:@,lun + * Make sure not to call usal_scandev() + */ + devp = NULL; + } else if (devp[0] == '\0') { + /* + * Got USCSI: or ATAPI: + * Make sure not to call usal_scandev() + */ + devp = NULL; + } else if (strchr(sdev, ',') == NULL) { + /* We may come here with 'ATAPI:/dev/hdc' */ + strncpy(devname, scsidev, + sizeof (devname)-1); + devname[sizeof (devname)-1] = '\0'; + n = -1; + lun = -2; /* Lun must be known */ + /* + * Make sure not to call usal_scandev() + */ + devp = NULL; + } + } + } +nulldevice: + +/*fprintf(stderr, "10 scsidev '%s' sdev '%s' devp '%s' b: %d t: %d l: %d\n", scsidev, sdev, devp, bus, tgt, lun);*/ + + if (devp != NULL) { + n = usal_scandev(devp, errs, slen, &bus, &tgt, &lun); + if (n < 0) { + errno = EINVAL; + return ((SCSI *)0); + } + } + if (n >= 1 && n <= 3) { /* Got bus,target,lun or target,lun or tgt*/ + usal_settarget(usalp, bus, tgt, lun); + } else if (n == -1) { /* Got device:@, fetch bus/lun from OS */ + usal_settarget(usalp, -2, -2, lun); + } else if (devp != NULL) { + /* + * XXX May this happen after we allow tgt to repesent tgt,0 ? + */ + fprintf(stderr, "WARNING: device not valid, trying to use default target...\n"); + usal_settarget(usalp, 0, 6, 0); + } + if (be_verbose && scsidev != NULL) { + fprintf(stderr, "scsidev: '%s'\n", scsidev); + if (devname[0] != '\0') + fprintf(stderr, "devname: '%s'\n", devname); + fprintf(stderr, "scsibus: %d target: %d lun: %d\n", + usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp)); + } + if (debug > 0) { + fprintf(stderr, "usal__open(%s) %d,%d,%d\n", + devname, + usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp)); + } + if (usal__open(usalp, devname) <= 0) { + if (errs && usalp->errstr) + snprintf(errs, slen, "%s", usalp->errstr); + usal_sfree(usalp); + return ((SCSI *)0); + } + return (usalp); +} + +int +usal_help(FILE *f) +{ + SCSI *usalp; + + usalp = usal_smalloc(); + if (usalp != NULL) { +extern usal_ops_t usal_std_ops; + + usalp->ops = &usal_std_ops; + + printf("Supported SCSI transports for this platform:\n"); + SCGO_HELP(usalp, f); + usal_remote()->usalo_help(usalp, f); + usal_sfree(usalp); + } + return (0); +} + +/* + * Convert target,lun or scsibus,target,lun syntax. + * Check for bad syntax and invalid values. + * This is definitely better than using scanf() as it checks for syntax errors. + */ +static int +usal_scandev(char *devp, char *errs, int slen, int *busp, int *tgtp, int *lunp) +{ + int x1, x2, x3; + int n = 0; + char *p = devp; + + x1 = x2 = x3 = 0; + *busp = *tgtp = *lunp = 0; + + if (*p != '\0') { + p = astoi(p, &x1); + if (*p == ',') { + p++; + n++; + } else { + if (errs) + snprintf(errs, slen, "Invalid bus or target specifier in '%s'", devp); + return (-1); + } + } + if (*p != '\0') { + p = astoi(p, &x2); + if (*p == ',' || *p == '\0') { + if (*p != '\0') + p++; + n++; + } else { + if (errs) + snprintf(errs, slen, "Invalid target or lun specifier in '%s'", devp); + return (-1); + } + } + if (*p != '\0') { + p = astoi(p, &x3); + if (*p == '\0') { + n++; + } else { + if (errs) + snprintf(errs, slen, "Invalid lun specifier in '%s'", devp); + return (-1); + } + } + if (n == 3) { + *busp = x1; + *tgtp = x2; + *lunp = x3; + } + if (n == 2) { + *tgtp = x1; + *lunp = x2; + } + if (n == 1) { + *tgtp = x1; + } + + if (x1 < 0 || x2 < 0 || x3 < 0) { + if (errs) + snprintf(errs, slen, "Invalid value for bus, target or lun (%d,%d,%d)", + *busp, *tgtp, *lunp); + return (-1); + } + return (n); +} + +int +usal_close(SCSI *usalp) +{ + usal__close(usalp); + usal_sfree(usalp); + return (0); +} + +char * usal_natname(SCSI *usalp, int busno, int tgt, int tlun) { + return usalp->ops->usalo_natname(usalp, busno, tgt, tlun); +} + +int usal_fileno(SCSI *usalp, int busno, int tgt, int tlun) { + return usalp->ops->usalo_fileno(usalp, busno, tgt, tlun); +} + +void +usal_settimeout(SCSI *usalp, int timeout) +{ +#ifdef nonono + if (timeout >= 0) + usalp->deftimeout = timeout; +#else + usalp->deftimeout = timeout; +#endif +} + +SCSI * +usal_smalloc() +{ + SCSI *usalp; +extern usal_ops_t usal_dummy_ops; + + usalp = (SCSI *)malloc(sizeof (*usalp)); + if (usalp == NULL) + return ((SCSI *)0); + + fillbytes(usalp, sizeof (*usalp), 0); + usalp->ops = &usal_dummy_ops; + usal_settarget(usalp, -1, -1, -1); + usalp->fd = -1; + usalp->deftimeout = 20; + usalp->running = FALSE; + + usalp->cmdstart = (struct timeval *)malloc(sizeof (struct timeval)); + if (usalp->cmdstart == NULL) + goto err; + usalp->cmdstop = (struct timeval *)malloc(sizeof (struct timeval)); + if (usalp->cmdstop == NULL) + goto err; + usalp->scmd = (struct usal_cmd *)malloc(sizeof (struct usal_cmd)); + if (usalp->scmd == NULL) + goto err; + usalp->errstr = malloc(SCSI_ERRSTR_SIZE); + if (usalp->errstr == NULL) + goto err; + usalp->errptr = usalp->errbeg = usalp->errstr; + usalp->errstr[0] = '\0'; + usalp->errfile = (void *)stderr; + usalp->inq = (struct scsi_inquiry *)malloc(sizeof (struct scsi_inquiry)); + if (usalp->inq == NULL) + goto err; + usalp->cap = (struct scsi_capacity *)malloc(sizeof (struct scsi_capacity)); + if (usalp->cap == NULL) + goto err; + + return (usalp); +err: + usal_sfree(usalp); + return ((SCSI *)0); +} + +void +usal_sfree(SCSI *usalp) +{ + if (usalp->cmdstart) + free(usalp->cmdstart); + if (usalp->cmdstop) + free(usalp->cmdstop); + if (usalp->scmd) + free(usalp->scmd); + if (usalp->inq) + free(usalp->inq); + if (usalp->cap) + free(usalp->cap); + if (usalp->local) + free(usalp->local); + usal_freebuf(usalp); + if (usalp->errstr) + free(usalp->errstr); + free(usalp); +} diff --git a/libusal/scsitransp.c b/libusal/scsitransp.c new file mode 100644 index 0000000..b3cc502 --- /dev/null +++ b/libusal/scsitransp.c @@ -0,0 +1,1345 @@ +/* + * 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. + * + */ + +/* @(#)scsitransp.c 1.91 04/06/17 Copyright 1988,1995,2000-2004 J. Schilling */ +/*#ifndef lint*/ +static char sccsid[] = + "@(#)scsitransp.c 1.91 04/06/17 Copyright 1988,1995,2000-2004 J. Schilling"; +/*#endif*/ +/* + * SCSI user level command transport routines (generic part). + * + * 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. + * + * Copyright (c) 1988,1995,2000-2004 J. Schilling + */ +/* + * 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. + */ + +#include <mconfig.h> +#include <stdio.h> +#include <standard.h> +#include <stdxlib.h> +#include <unixstd.h> +#include <errno.h> +#include <timedefs.h> +#include <strdefs.h> +#include <schily.h> + +#include <usal/usalcmd.h> +#include <usal/scsireg.h> +#include <usal/scsitransp.h> +#include "usaltimes.h" + +#include <stdarg.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_version[] = CDRKIT_VERSION; /* The global libusal version */ +static char _usal_auth_cdrkit[] = "Cdrkit"; /* The author for this module */ + +#define DEFTIMEOUT 20 /* Default timeout for SCSI command transport */ + +char *usal_version(SCSI *usalp, int what); +int usal__open(SCSI *usalp, char *device); +int usal__close(SCSI *usalp); +BOOL usal_havebus(SCSI *usalp, int); +int usal_initiator_id(SCSI *usalp); +int usal_isatapi(SCSI *usalp); +int usal_reset(SCSI *usalp, int what); +void *usal_getbuf(SCSI *usalp, long); +void usal_freebuf(SCSI *usalp); +long usal_bufsize(SCSI *usalp, long); +void usal_setnonstderrs(SCSI *usalp, const char **); +BOOL usal_yes(char *); +#ifdef nonono +static void usal_sighandler(int); +#endif +int usal_cmd(SCSI *usalp); +void usal_vhead(SCSI *usalp); +int usal_svhead(SCSI *usalp, char *buf, int maxcnt); +int usal_vtail(SCSI *usalp); +int usal_svtail(SCSI *usalp, int *retp, char *buf, int maxcnt); +void usal_vsetup(SCSI *usalp); +int usal_getresid(SCSI *usalp); +int usal_getdmacnt(SCSI *usalp); +BOOL usal_cmd_err(SCSI *usalp); +void usal_printerr(SCSI *usalp); +void usal_fprinterr(SCSI *usalp, FILE *f); +int usal_sprinterr(SCSI *usalp, char *buf, int maxcnt); +int usal__sprinterr(SCSI *usalp, char *buf, int maxcnt); +void usal_printcdb(SCSI *usalp); +int usal_sprintcdb(SCSI *usalp, char *buf, int maxcnt); +void usal_printwdata(SCSI *usalp); +int usal_sprintwdata(SCSI *usalp, char *buf, int maxcnt); +void usal_printrdata(SCSI *usalp); +int usal_sprintrdata(SCSI *usalp, char *buf, int maxcnt); +void usal_printresult(SCSI *usalp); +int usal_sprintresult(SCSI *usalp, char *buf, int maxcnt); +void usal_printstatus(SCSI *usalp); +int usal_sprintstatus(SCSI *usalp, char *buf, int maxcnt); +void usal_fprbytes(FILE *, char *, unsigned char *, int); +void usal_fprascii(FILE *, char *, unsigned char *, int); +void usal_prbytes(char *, unsigned char *, int); +void usal_prascii(char *, unsigned char *, int); +int usal_sprbytes(char *buf, int maxcnt, char *, unsigned char *, int); +int usal_sprascii(char *buf, int maxcnt, char *, unsigned char *, int); +void usal_fprsense(FILE *f, unsigned char *, int); +int usal_sprsense(char *buf, int maxcnt, unsigned char *, int); +void usal_prsense(unsigned char *, int); +int usal_cmd_status(SCSI *usalp); +int usal_sense_key(SCSI *usalp); +int usal_sense_code(SCSI *usalp); +int usal_sense_qual(SCSI *usalp); +unsigned char *usal_sense_table(SCSI *usalp); +void usal_fprintdev(FILE *, struct scsi_inquiry *); +void usal_printdev(struct scsi_inquiry *); +int usal_printf(SCSI *usalp, const char *form, ...); +int usal_errflush(SCSI *usalp); +int usal_errfflush(SCSI *usalp, FILE *f); + +/* + * Return version information for the SCSI transport code. + * This has been introduced to make it easier to trace down problems + * in applications. + * + * If usalp is NULL, return general library version information. + * If usalp is != NULL, return version information for the low level transport. + */ +char * +usal_version(SCSI *usalp, int what) +{ + if (usalp == (SCSI *)0) { + switch (what) { + + case SCG_VERSION: + return (_usal_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); + default: + return ((char *)0); + } + } + return (SCGO_VERSION(usalp, what)); +} + +/* + * Call low level SCSI open routine from transport abstraction layer. + */ +int +usal__open(SCSI *usalp, char *device) +{ + int ret; + usal_ops_t *ops; +extern usal_ops_t usal_std_ops; + + usalp->ops = &usal_std_ops; + + if (device && strncmp(device, "REMOTE", 6) == 0) { + ops = usal_remote(); + if (ops != NULL) + usalp->ops = ops; + } + + ret = SCGO_OPEN(usalp, device); + if (ret < 0) + return (ret); + + /* + * Now make usalp->fd valid if possible. + * Note that usal_scsibus(usalp)/usal_target(usalp)/usal_lun(usalp) may have + * changed in SCGO_OPEN(). + */ + usal_settarget(usalp, usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp)); + return (ret); +} + +/* + * Call low level SCSI close routine from transport abstraction layer. + */ +int +usal__close(SCSI *usalp) +{ + return (SCGO_CLOSE(usalp)); +} + +/* + * Retrieve max DMA count for this target. + */ +long +usal_bufsize(SCSI *usalp, long amt) +{ + long maxdma; + + maxdma = SCGO_MAXDMA(usalp, amt); + if (amt <= 0 || amt > maxdma) + amt = maxdma; + + usalp->maxdma = maxdma; /* Max possible */ + usalp->maxbuf = amt; /* Current value */ + + return (amt); +} + +/* + * Allocate a buffer that may be used for DMA. + */ +void * +usal_getbuf(SCSI *usalp, long amt) +{ + void *buf; + + if (amt <= 0 || amt > usal_bufsize(usalp, amt)) + return ((void *)0); + + buf = SCGO_GETBUF(usalp, amt); + usalp->bufptr = buf; + return (buf); +} + +/* + * Free DMA buffer. + */ +void +usal_freebuf(SCSI *usalp) +{ + SCGO_FREEBUF(usalp); + usalp->bufptr = NULL; +} + +/* + * Check if 'busno' is a valid SCSI bus number. + */ +BOOL +usal_havebus(SCSI *usalp, int busno) +{ + return (SCGO_HAVEBUS(usalp, busno)); +} + +/* + * Return SCSI initiator ID for current SCSI bus if available. + */ +int +usal_initiator_id(SCSI *usalp) +{ + return (SCGO_INITIATOR_ID(usalp)); +} + +/* + * Return a hint whether current SCSI target refers to a ATAPI device. + */ +int +usal_isatapi(SCSI *usalp) +{ + return (SCGO_ISATAPI(usalp)); +} + +/* + * Reset SCSI bus or target. + */ +int +usal_reset(SCSI *usalp, int what) +{ + return (SCGO_RESET(usalp, what)); +} + +/* + * Set up nonstd error vector for curren target. + * To clear additional error table, call usal_setnonstderrs(usalp, NULL); + * Note: do not use this when scanning the SCSI bus. + */ +void +usal_setnonstderrs(SCSI *usalp, const char **vec) +{ + usalp->nonstderrs = vec; +} + +/* + * Simple Yes/No answer checker. + */ +BOOL +usal_yes(char *msg) +{ + char okbuf[10]; + + printf("%s", msg); + flush(); + if (rols_getline(okbuf, sizeof (okbuf)) == EOF) + exit(EX_BAD); + if (streql(okbuf, "y") || streql(okbuf, "yes") || + streql(okbuf, "Y") || streql(okbuf, "YES")) + return (TRUE); + else + return (FALSE); +} + +#ifdef nonono +static void +usal_sighandler(int sig) +{ + printf("\n"); + if (scsi_running) { + printf("Running command: %s\n", scsi_command); + printf("Resetting SCSI - Bus.\n"); + if (usal_reset(usalp) < 0) + errmsg("Cannot reset SCSI - Bus.\n"); + } + if (usal_yes("EXIT ? ")) + exit(sig); +} +#endif + +/* + * Send a SCSI command. + * Do error checking and reporting depending on the values of + * usalp->verbose, usalp->debug and usalp->silent. + */ +int +usal_cmd(SCSI *usalp) +{ + int ret; + register struct usal_cmd *scmd = usalp->scmd; + + /* + * Reset old error messages in usalp->errstr + */ + usalp->errptr = usalp->errbeg = usalp->errstr; + + scmd->kdebug = usalp->kdebug; + if (scmd->timeout == 0 || scmd->timeout < usalp->deftimeout) + scmd->timeout = usalp->deftimeout; + if (usalp->disre_disable) + scmd->flags &= ~SCG_DISRE_ENA; + if (usalp->noparity) + scmd->flags |= SCG_NOPARITY; + + scmd->u_sense.cmd_sense[0] = 0; /* Paranioa */ + if (scmd->sense_len > SCG_MAX_SENSE) + scmd->sense_len = SCG_MAX_SENSE; + else if (scmd->sense_len < 0) + scmd->sense_len = 0; + + if (usalp->verbose) { + usal_vhead(usalp); + usal_errflush(usalp); + } + + if (usalp->running) { + if (usalp->curcmdname) { + fprintf(stderr, "Currently running '%s' command.\n", + usalp->curcmdname); + } + raisecond("SCSI ALREADY RUNNING !!", 0L); + } + usalp->cb_fun = NULL; + gettimeofday(usalp->cmdstart, (struct timezone *)0); + usalp->curcmdname = usalp->cmdname; + usalp->running = TRUE; + ret = SCGO_SEND(usalp); + usalp->running = FALSE; + __usal_times(usalp); + if (ret < 0) { + /* + * Old /dev/usal versions will not allow to access targets > 7. + * Include a workaround to make this non fatal. + */ + if (usal_target(usalp) < 8 || geterrno() != EINVAL) + comerr("Cannot send SCSI cmd via ioctl\n"); + if (scmd->ux_errno == 0) + scmd->ux_errno = geterrno(); + if (scmd->error == SCG_NO_ERROR) + scmd->error = SCG_FATAL; + if (usalp->debug > 0) { + errmsg("ret < 0 errno: %d ux_errno: %d error: %d\n", + geterrno(), scmd->ux_errno, scmd->error); + } + } + + ret = usal_vtail(usalp); + usal_errflush(usalp); + if (usalp->cb_fun != NULL) + (*usalp->cb_fun)(usalp->cb_arg); + return (ret); +} + +/* + * Fill the head of verbose printing into the SCSI error buffer. + * Action depends on SCSI verbose status. + */ +void +usal_vhead(SCSI *usalp) +{ + usalp->errptr += usal_svhead(usalp, usalp->errptr, usal_errrsize(usalp)); +} + +/* + * Fill the head of verbose printing into a buffer. + * Action depends on SCSI verbose status. + */ +int +usal_svhead(SCSI *usalp, char *buf, int maxcnt) +{ + register char *p = buf; + register int amt; + + if (usalp->verbose <= 0) + return (0); + + amt = snprintf(p, maxcnt, + "\nExecuting '%s' command on Bus %d Target %d, Lun %d timeout %ds\n", + /* XXX Really this ??? */ +/* usalp->cmdname, usal_scsibus(usalp), usal_target(usalp), usalp->scmd->cdb.g0_cdb.lun,*/ + usalp->cmdname, usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp), + usalp->scmd->timeout); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + + amt = usal_sprintcdb(usalp, p, maxcnt); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + + if (usalp->verbose > 1) { + amt = usal_sprintwdata(usalp, p, maxcnt); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + } + return (p - buf); +} + +/* + * Fill the tail of verbose printing into the SCSI error buffer. + * Action depends on SCSI verbose status. + */ +int +usal_vtail(SCSI *usalp) +{ + int ret; + + usalp->errptr += usal_svtail(usalp, &ret, usalp->errptr, usal_errrsize(usalp)); + return (ret); +} + +/* + * Fill the tail of verbose printing into a buffer. + * Action depends on SCSI verbose status. + */ +int +usal_svtail(SCSI *usalp, int *retp, char *buf, int maxcnt) +{ + register char *p = buf; + register int amt; + int ret; + + ret = usal_cmd_err(usalp) ? -1 : 0; + if (retp) + *retp = ret; + if (ret) { + if (usalp->silent <= 0 || usalp->verbose) { + amt = usal__sprinterr(usalp, p, maxcnt); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + } + } + if ((usalp->silent <= 0 || usalp->verbose) && usalp->scmd->resid) { + if (usalp->scmd->resid < 0) { + /* + * An operating system that does DMA the right way + * will not allow DMA overruns - it will stop DMA + * before bad things happen. + * A DMA residual count < 0 (-1) is a hint for a DMA + * overrun but does not affect the transfer count. + */ + amt = snprintf(p, maxcnt, "DMA overrun, "); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + } + amt = snprintf(p, maxcnt, "resid: %d\n", usalp->scmd->resid); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + } + if (usalp->verbose > 0 || (ret < 0 && usalp->silent <= 0)) { + amt = usal_sprintresult(usalp, p, maxcnt); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + } + return (p - buf); +} + +/* + * Set up SCSI error buffer with verbose print data. + * Action depends on SCSI verbose status. + */ +void +usal_vsetup(SCSI *usalp) +{ + usal_vhead(usalp); + usal_vtail(usalp); +} + +/* + * Return the residual DMA count for last command. + * If this count is < 0, then a DMA overrun occured. + */ +int +usal_getresid(SCSI *usalp) +{ + return (usalp->scmd->resid); +} + +/* + * Return the actual DMA count for last command. + */ +int +usal_getdmacnt(SCSI *usalp) +{ + register struct usal_cmd *scmd = usalp->scmd; + + if (scmd->resid < 0) + return (scmd->size); + + return (scmd->size - scmd->resid); +} + +/* + * Test if last SCSI command got an error. + */ +BOOL +usal_cmd_err(SCSI *usalp) +{ + register struct usal_cmd *cp = usalp->scmd; + + if (cp->error != SCG_NO_ERROR || + cp->ux_errno != 0 || + *(Uchar *)&cp->scb != 0 || + cp->u_sense.cmd_sense[0] != 0) /* Paranioa */ + return (TRUE); + return (FALSE); +} + +/* + * Used to print error messges if the command itself has been run silently. + * + * print the following SCSI codes: + * + * - command transport status + * - CDB + * - SCSI status byte + * - Sense Bytes + * - Decoded Sense data + * - DMA status + * - SCSI timing + * + * to SCSI errfile. + */ +void +usal_printerr(SCSI *usalp) +{ + usal_fprinterr(usalp, (FILE *)usalp->errfile); +} + +/* + * print the following SCSI codes: + * + * - command transport status + * - CDB + * - SCSI status byte + * - Sense Bytes + * - Decoded Sense data + * - DMA status + * - SCSI timing + * + * to a file. + */ +void +usal_fprinterr(SCSI *usalp, FILE *f) +{ + char errbuf[SCSI_ERRSTR_SIZE]; + int amt; + + amt = usal_sprinterr(usalp, errbuf, sizeof (errbuf)); + if (amt > 0) { + filewrite(f, errbuf, amt); + fflush(f); + } +} + +/* + * print the following SCSI codes: + * + * - command transport status + * - CDB + * - SCSI status byte + * - Sense Bytes + * - Decoded Sense data + * - DMA status + * - SCSI timing + * + * into a buffer. + */ +int +usal_sprinterr(SCSI *usalp, char *buf, int maxcnt) +{ + int amt; + int osilent = usalp->silent; + int overbose = usalp->verbose; + + usalp->silent = 0; + usalp->verbose = 0; + amt = usal_svtail(usalp, NULL, buf, maxcnt); + usalp->silent = osilent; + usalp->verbose = overbose; + return (amt); +} + +/* + * print the following SCSI codes: + * + * - command transport status + * - CDB + * - SCSI status byte + * - Sense Bytes + * - Decoded Sense data + * + * into a buffer. + */ +int +usal__sprinterr(SCSI *usalp, char *buf, int maxcnt) +{ + register struct usal_cmd *cp = usalp->scmd; + register char *err; + char *cmdname = "SCSI command name not set by caller"; + char errbuf[64]; + register char *p = buf; + register int amt; + + switch (cp->error) { + + case SCG_NO_ERROR : err = "no error"; break; + case SCG_RETRYABLE: err = "retryable error"; break; + case SCG_FATAL : err = "fatal error"; break; + /* + * We need to cast timeval->* to long because + * of the broken sys/time.h in Linux. + */ + case SCG_TIMEOUT : snprintf(errbuf, sizeof (errbuf), + "cmd timeout after %ld.%03ld (%d) s", + (long)usalp->cmdstop->tv_sec, + (long)usalp->cmdstop->tv_usec/1000, + cp->timeout); + err = errbuf; + break; + default: snprintf(errbuf, sizeof (errbuf), + "error: %d", cp->error); + err = errbuf; + } + + if (usalp->cmdname != NULL && usalp->cmdname[0] != '\0') + cmdname = usalp->cmdname; + /*amt = serrmsgno(cp->ux_errno, p, maxcnt, "%s: scsi sendcmd: %s\n", cmdname, err); + if (amt < 0) + return (amt); + */ + amt=snprintf(p, maxcnt, "Errno: %d (%s), %s scsi sendcmd: %s\n", cp->ux_errno, strerror(cp->ux_errno), cmdname, err); + if(amt>=maxcnt || amt<0) + return (amt); + p += amt; + maxcnt -= amt; + + amt = usal_sprintcdb(usalp, p, maxcnt); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + + if (cp->error <= SCG_RETRYABLE) { + amt = usal_sprintstatus(usalp, p, maxcnt); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + } + + if (cp->scb.chk) { + amt = usal_sprsense(p, maxcnt, (Uchar *)&cp->sense, cp->sense_count); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + amt = usal__errmsg(usalp, p, maxcnt, &cp->sense, &cp->scb, -1); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + } + return (p - buf); +} + +/* + * XXX Do we need this function? + * + * print the SCSI Command descriptor block to XXX stderr. + */ +void +usal_printcdb(SCSI *usalp) +{ + usal_prbytes("CDB: ", usalp->scmd->cdb.cmd_cdb, usalp->scmd->cdb_len); +} + +/* + * print the SCSI Command descriptor block into a buffer. + */ +int +usal_sprintcdb(SCSI *usalp, char *buf, int maxcnt) +{ + int cnt; + + cnt = usal_sprbytes(buf, maxcnt, "CDB: ", usalp->scmd->cdb.cmd_cdb, usalp->scmd->cdb_len); + if (cnt < 0) + cnt = 0; + return (cnt); +} + +/* + * XXX Do we need this function? + * XXX usal_printrdata() is used. + * XXX We need to check if we should write to stderr or better to usal->errfile + * + * print the SCSI send data to stderr. + */ +void +usal_printwdata(SCSI *usalp) +{ + register struct usal_cmd *scmd = usalp->scmd; + + if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) == 0) { + fprintf(stderr, "Sending %d (0x%X) bytes of data.\n", + scmd->size, scmd->size); + usal_prbytes("Write Data: ", + (Uchar *)scmd->addr, + scmd->size > 100 ? 100 : scmd->size); + } +} + +/* + * print the SCSI send data into a buffer. + */ +int +usal_sprintwdata(SCSI *usalp, char *buf, int maxcnt) +{ + register struct usal_cmd *scmd = usalp->scmd; + register char *p = buf; + register int amt; + + if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) == 0) { + amt = snprintf(p, maxcnt, + "Sending %d (0x%X) bytes of data.\n", + scmd->size, scmd->size); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + amt = usal_sprbytes(p, maxcnt, "Write Data: ", + (Uchar *)scmd->addr, + scmd->size > 100 ? 100 : scmd->size); + if (amt < 0) + return (amt); + p += amt; + } + return (p - buf); +} + +/* + * XXX We need to check if we should write to stderr or better to usal->errfile + * + * print the SCSI received data to stderr. + */ +void +usal_printrdata(SCSI *usalp) +{ + register struct usal_cmd *scmd = usalp->scmd; + register int trcnt = usal_getdmacnt(usalp); + + if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) != 0) { + fprintf(stderr, "Got %d (0x%X), expecting %d (0x%X) bytes of data.\n", + trcnt, trcnt, + scmd->size, scmd->size); + usal_prbytes("Received Data: ", + (Uchar *)scmd->addr, + trcnt > 100 ? 100 : trcnt); + } +} + +/* + * print the SCSI received data into a buffer. + */ +int +usal_sprintrdata(SCSI *usalp, char *buf, int maxcnt) +{ + register struct usal_cmd *scmd = usalp->scmd; + register char *p = buf; + register int amt; + register int trcnt = usal_getdmacnt(usalp); + + if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) != 0) { + amt = snprintf(p, maxcnt, + "Got %d (0x%X), expecting %d (0x%X) bytes of data.\n", + trcnt, trcnt, + scmd->size, scmd->size); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + amt = usal_sprbytes(p, maxcnt, + "Received Data: ", + (Uchar *)scmd->addr, + trcnt > 100 ? 100 : trcnt); + if (amt < 0) + return (amt); + p += amt; + } + return (p - buf); +} + +/* + * XXX We need to check if we should write to stderr or better to usal->errfile + * + * print the SCSI timings and (depending on verbose) received data to stderr. + */ +void +usal_printresult(SCSI *usalp) +{ + fprintf(stderr, "cmd finished after %ld.%03lds timeout %ds\n", + (long)usalp->cmdstop->tv_sec, + (long)usalp->cmdstop->tv_usec/1000, + usalp->scmd->timeout); + if (usalp->verbose > 1) + usal_printrdata(usalp); + flush(); +} + +/* + * print the SCSI timings and (depending on verbose) received data into a buffer. + */ +int +usal_sprintresult(SCSI *usalp, char *buf, int maxcnt) +{ + register char *p = buf; + register int amt; + + amt = snprintf(p, maxcnt, + "cmd finished after %ld.%03lds timeout %ds\n", + (long)usalp->cmdstop->tv_sec, + (long)usalp->cmdstop->tv_usec/1000, + usalp->scmd->timeout); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + if (usalp->verbose > 1) { + amt = usal_sprintrdata(usalp, p, maxcnt); + if (amt < 0) + return (amt); + p += amt; + } + return (p - buf); +} + +/* + * XXX Do we need this function? + * + * print the SCSI status byte in human readable form to the SCSI error file. + */ +void +usal_printstatus(SCSI *usalp) +{ + char errbuf[SCSI_ERRSTR_SIZE]; + int amt; + + amt = usal_sprintstatus(usalp, errbuf, sizeof (errbuf)); + if (amt > 0) { + filewrite((FILE *)usalp->errfile, errbuf, amt); + fflush((FILE *)usalp->errfile); + } +} + +/* + * print the SCSI status byte in human readable form into a buffer. + */ +int +usal_sprintstatus(SCSI *usalp, char *buf, int maxcnt) +{ + register struct usal_cmd *cp = usalp->scmd; + char *err; + char *err2 = ""; + register char *p = buf; + register int amt; + + amt = snprintf(p, maxcnt, "status: 0x%x ", *(Uchar *)&cp->scb); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; +#ifdef SCSI_EXTENDED_STATUS + if (cp->scb.ext_st1) { + amt = snprintf(p, maxcnt, "0x%x ", ((Uchar *)&cp->scb)[1]); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + } + if (cp->scb.ext_st2) { + amt = snprintf(p, maxcnt, "0x%x ", ((Uchar *)&cp->scb)[2]); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + } +#endif + switch (*(Uchar *)&cp->scb & 036) { + + case 0 : err = "GOOD STATUS"; break; + case 02 : err = "CHECK CONDITION"; break; + case 04 : err = "CONDITION MET/GOOD"; break; + case 010: err = "BUSY"; break; + case 020: err = "INTERMEDIATE GOOD STATUS"; break; + case 024: err = "INTERMEDIATE CONDITION MET/GOOD"; break; + case 030: err = "RESERVATION CONFLICT"; break; + default : err = "Reserved"; break; + } +#ifdef SCSI_EXTENDED_STATUS + if (cp->scb.ext_st1 && cp->scb.ha_er) + err2 = " host adapter detected error"; +#endif + amt = snprintf(p, maxcnt, "(%s%s)\n", err, err2); + if (amt < 0) + return (amt); + p += amt; + return (p - buf); +} + +/* + * print some bytes in hex to a file. + */ +void +usal_fprbytes(FILE *f, char *s, register Uchar *cp, register int n) +{ + fprintf(f, "%s", s); + while (--n >= 0) + fprintf(f, " %02X", *cp++); + fprintf(f, "\n"); +} + +/* + * print some bytes in ascii to a file. + */ +void +usal_fprascii(FILE *f, char *s, register Uchar *cp, register int n) +{ + register int c; + + fprintf(f, "%s", s); + while (--n >= 0) { + c = *cp++; + if (c >= ' ' && c < 0177) + fprintf(f, "%c", c); + else + fprintf(f, "."); + } + fprintf(f, "\n"); +} + +/* + * XXX We need to check if we should write to stderr or better to usal->errfile + * + * print some bytes in hex to stderr. + */ +void +usal_prbytes(char *s, register Uchar *cp, register int n) +{ + usal_fprbytes(stderr, s, cp, n); +} + +/* + * XXX We need to check if we should write to stderr or better to usal->errfile + * + * print some bytes in ascii to stderr. + */ +void +usal_prascii(char *s, register Uchar *cp, register int n) +{ + usal_fprascii(stderr, s, cp, n); +} + +/* + * print some bytes in hex into a buffer. + */ +int +usal_sprbytes(char *buf, int maxcnt, char *s, register Uchar *cp, register int n) +{ + register char *p = buf; + register int amt; + + amt = snprintf(p, maxcnt, "%s", s); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + + while (--n >= 0) { + amt = snprintf(p, maxcnt, " %02X", *cp++); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + } + amt = snprintf(p, maxcnt, "\n"); + if (amt < 0) + return (amt); + p += amt; + return (p - buf); +} + +/* + * print some bytes in ascii into a buffer. + */ +int +usal_sprascii(char *buf, int maxcnt, char *s, register Uchar *cp, register int n) +{ + register char *p = buf; + register int amt; + register int c; + + amt = snprintf(p, maxcnt, "%s", s); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + + while (--n >= 0) { + c = *cp++; + if (c >= ' ' && c < 0177) + amt = snprintf(p, maxcnt, "%c", c); + else + amt = snprintf(p, maxcnt, "."); + if (amt < 0) + return (amt); + p += amt; + maxcnt -= amt; + } + amt = snprintf(p, maxcnt, "\n"); + if (amt < 0) + return (amt); + p += amt; + return (p - buf); +} + +/* + * print the SCSI sense data for last command in hex to a file. + */ +void +usal_fprsense(FILE *f, Uchar *cp, int n) +{ + usal_fprbytes(f, "Sense Bytes:", cp, n); +} + +/* + * XXX We need to check if we should write to stderr or better to usal->errfile + * + * print the SCSI sense data for last command in hex to stderr. + */ +void +usal_prsense(Uchar *cp, int n) +{ + usal_fprsense(stderr, cp, n); +} + +/* + * print the SCSI sense data for last command in hex into a buffer. + */ +int +usal_sprsense(char *buf, int maxcnt, Uchar *cp, int n) +{ + return (usal_sprbytes(buf, maxcnt, "Sense Bytes:", cp, n)); +} + +/* + * Return the SCSI status byte for last command. + */ +int +usal_cmd_status(SCSI *usalp) +{ + struct usal_cmd *cp = usalp->scmd; + int cmdstatus = *(Uchar *)&cp->scb; + + return (cmdstatus); +} + +/* + * Return the SCSI sense key for last command. + */ +int +usal_sense_key(SCSI *usalp) +{ + register struct usal_cmd *cp = usalp->scmd; + int key = -1; + + if (!usal_cmd_err(usalp)) + return (0); + + if (cp->sense.code >= 0x70) + key = ((struct scsi_ext_sense *)&(cp->sense))->key; + return (key); +} + +/* + * Return all the SCSI sense table last command. + */ +unsigned char * +usal_sense_table(SCSI *usalp) +{ + register struct usal_cmd *cp = usalp->scmd; + + if(!usal_cmd_err(usalp)) + return (0); + + /* if (cp->sense.code >= 0x70) */ + return (unsigned char *) &(cp->sense); +} + + +/* + * Return the SCSI sense code for last command. + */ +int +usal_sense_code(SCSI *usalp) +{ + register struct usal_cmd *cp = usalp->scmd; + int code = -1; + + if (!usal_cmd_err(usalp)) + return (0); + + if (cp->sense.code >= 0x70) + code = ((struct scsi_ext_sense *)&(cp->sense))->sense_code; + else + code = cp->sense.code; + return (code); +} + +/* + * Return the SCSI sense qualifier for last command. + */ +int +usal_sense_qual(SCSI *usalp) +{ + register struct usal_cmd *cp = usalp->scmd; + + if (!usal_cmd_err(usalp)) + return (0); + + if (cp->sense.code >= 0x70) + return (((struct scsi_ext_sense *)&(cp->sense))->qual_code); + else + return (0); +} + +/* + * Print the device type from the SCSI inquiry buffer to file. + */ +void +usal_fprintdev(FILE *f, struct scsi_inquiry *ip) +{ + if (ip->removable) + fprintf(f, "Removable "); + if (ip->data_format >= 2) { + switch (ip->qualifier) { + + case INQ_DEV_PRESENT: + break; + case INQ_DEV_NOTPR: + fprintf(f, "not present "); + break; + case INQ_DEV_RES: + fprintf(f, "reserved "); + break; + case INQ_DEV_NOTSUP: + if (ip->type == INQ_NODEV) { + fprintf(f, "unsupported\n"); return; + } + fprintf(f, "unsupported "); + break; + default: + fprintf(f, "vendor specific %d ", + (int)ip->qualifier); + } + } + switch (ip->type) { + + case INQ_DASD: + fprintf(f, "Disk"); break; + case INQ_SEQD: + fprintf(f, "Tape"); break; + case INQ_PRTD: + fprintf(f, "Printer"); break; + case INQ_PROCD: + fprintf(f, "Processor"); break; + case INQ_WORM: + fprintf(f, "WORM"); break; + case INQ_ROMD: + fprintf(f, "CD-ROM"); break; + case INQ_SCAN: + fprintf(f, "Scanner"); break; + case INQ_OMEM: + fprintf(f, "Optical Storage"); break; + case INQ_JUKE: + fprintf(f, "Juke Box"); break; + case INQ_COMM: + fprintf(f, "Communication"); break; + case INQ_IT8_1: + fprintf(f, "IT8 1"); break; + case INQ_IT8_2: + fprintf(f, "IT8 2"); break; + case INQ_STARR: + fprintf(f, "Storage array"); break; + case INQ_ENCL: + fprintf(f, "Enclosure services"); break; + case INQ_SDAD: + fprintf(f, "Simple direct access"); break; + case INQ_OCRW: + fprintf(f, "Optical card r/w"); break; + case INQ_BRIDGE: + fprintf(f, "Bridging expander"); break; + case INQ_OSD: + fprintf(f, "Object based storage"); break; + case INQ_ADC: + fprintf(f, "Automation/Drive Interface"); break; + case INQ_WELLKNOWN: + fprintf(f, "Well known lun"); break; + + case INQ_NODEV: + if (ip->data_format >= 2) { + fprintf(f, "unknown/no device"); + break; + } else if (ip->qualifier == INQ_DEV_NOTSUP) { + fprintf(f, "unit not present"); + break; + } + default: + fprintf(f, "unknown device type 0x%x", + (int)ip->type); + } + fprintf(f, "\n"); +} + +/* + * Print the device type from the SCSI inquiry buffer to stdout. + */ +void +usal_printdev(struct scsi_inquiry *ip) +{ + usal_fprintdev(stdout, ip); +} + +/* + * print into the SCSI error buffer, adjust the next write pointer. + */ +/* VARARGS2 */ +int +usal_printf(SCSI *usalp, const char *form, ...) +{ + int cnt; + va_list args; + + va_start(args, form); + cnt = vsnprintf(usalp->errptr, usal_errrsize(usalp), form, args); + va_end(args); + + if (cnt < 0) { + usalp->errptr[0] = '\0'; + } else { + usalp->errptr += cnt; + } + return (cnt); +} + +/* + * Flush the SCSI error buffer to SCSI errfile. + * Clear error buffer after flushing. + */ +int +usal_errflush(SCSI *usalp) +{ + if (usalp->errfile == NULL) + return (0); + + return (usal_errfflush(usalp, (FILE *)usalp->errfile)); +} + +/* + * Flush the SCSI error buffer to a file. + * Clear error buffer after flushing. + */ +int +usal_errfflush(SCSI *usalp, FILE *f) +{ + int cnt; + + cnt = usalp->errptr - usalp->errbeg; + if (cnt > 0) { + filewrite(f, usalp->errbeg, cnt); + fflush(f); + usalp->errbeg = usalp->errptr; + } + return (cnt); +} diff --git a/libusal/usal/aspi-dos.h b/libusal/usal/aspi-dos.h new file mode 100644 index 0000000..3428ac8 --- /dev/null +++ b/libusal/usal/aspi-dos.h @@ -0,0 +1,169 @@ +/* + * 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. + * + */ + +/* @(#)aspi-dos.h 1.2 05/05/15 J. Schilling */ +#ifndef __ASPI16_H_ +#define __ASPI16_H_ + +#define PACKED __attribute__((packed)) +#define FAR +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; + +//***************************************************************************** +// %%% SCSI MISCELLANEOUS EQUATES %%% +//***************************************************************************** + +#define SENSE_LEN 14 // Default sense buffer length +#define SRB_DIR_SCSI 0x00 // Direction determined by SCSI +#define SRB_POSTING 0x01 // Enable ASPI posting +#define SRB_ENABLE_RESIDUAL_COUNT 0x04 // Enable residual byte count reporting +#define SRB_DIR_IN 0x08 // Transfer from SCSI target to host +#define SRB_DIR_OUT 0x10 // Transfer from host to SCSI target + +//***************************************************************************** +// %%% ASPI Command Definitions %%% +//***************************************************************************** + +#define SC_HA_INQUIRY 0x00 // Host adapter inquiry +#define SC_GET_DEV_TYPE 0x01 // Get device type +#define SC_EXEC_SCSI_CMD 0x02 // Execute SCSI command +#define SC_ABORT_SRB 0x03 // Abort an SRB +#define SC_RESET_DEV 0x04 // SCSI bus device reset +#define SC_SET_HA_PARMS 0x05 // Set HA parameters +#define SC_GET_DISK_INFO 0x06 // Get Disk information + +//***************************************************************************** +// %%% SRB Status %%% +//***************************************************************************** + +#define SS_PENDING 0x00 // SRB being processed +#define SS_COMP 0x01 // SRB completed without error +#define SS_ABORTED 0x02 // SRB aborted +#define SS_ABORT_FAIL 0x03 // Unable to abort SRB +#define SS_ERR 0x04 // SRB completed with error + +#define SS_INVALID_CMD 0x80 // Invalid ASPI command +#define SS_INVALID_HA 0x81 // Invalid host adapter number +#define SS_NO_DEVICE 0x82 // SCSI device not installed + +//***************************************************************************** +// %%% Host Adapter Status %%% +//***************************************************************************** + +#define HASTAT_OK 0x00 // Host adapter did not detect an + // error +#define HASTAT_SEL_TO 0x11 // Selection Timeout +#define HASTAT_DO_DU 0x12 // Data overrun data underrun +#define HASTAT_BUS_FREE 0x13 // Unexpected bus free +#define HASTAT_PHASE_ERR 0x14 // Target bus phase sequence + // failure +#define HASTAT_TIMEOUT 0x09 // Timed out while SRB was + // waiting to beprocessed. +#define HASTAT_COMMAND_TIMEOUT 0x0B // Adapter timed out processing SRB. +#define HASTAT_MESSAGE_REJECT 0x0D // While processing SRB, the + // adapter received a MESSAGE +#define HASTAT_BUS_RESET 0x0E // A bus reset was detected. +#define HASTAT_PARITY_ERROR 0x0F // A parity error was detected. +#define HASTAT_REQUEST_SENSE_FAILED 0x10 // The adapter failed in issuing + +typedef struct { + + BYTE Cmd; // 00/000 ASPI command code = SC_EXEC_SCSI_CMD + BYTE Status; // 01/001 ASPI command status byte + BYTE HaId; // 02/002 ASPI host adapter number + BYTE Flags; // 03/003 ASPI request flags + DWORD Hdr_Rsvd; // 04/004 Reserved, MUST = 0 + + union { + + struct { + + BYTE Count; // 08/008 Number of host adapters present + BYTE SCSI_ID; // 09/009 SCSI ID of host adapter + BYTE ManagerId[16]; // 0A/010 String describing the manager + BYTE Identifier[16]; // 1A/026 String describing the host adapter + BYTE Unique[16]; // 2A/042 Host Adapter Unique parameters + BYTE ExtBuffer[8]; // 3A/058 Extended inquiry data + + } PACKED HAInquiry; + + struct { + + BYTE Target; // 08/008 Target's SCSI ID + BYTE Lun; // 09/009 Target's LUN number + BYTE DeviceType; // 0A/010 Target's peripheral device type + + } PACKED GetDeviceType; + + struct { + + BYTE Target; // 08/008 Target's SCSI ID + BYTE Lun; // 09/009 Target's LUN number + DWORD BufLen; // 0A/010 Data Allocation Length + BYTE SenseLen; // 0E/014 Sense Allocation Length + BYTE FAR *BufPointer; // 0F/015 Data Buffer Pointer + DWORD Rsvd1; // 13/019 Reserved, MUST = 0 + BYTE CDBLen; // 17/023 CDB Length = 6/10/12 + BYTE HaStat; // 18/024 Host Adapter Status + BYTE TargStat; // 19/025 Target Status + VOID FAR *PostProc; // 1A/026 Post routine + BYTE Rsvd2[34]; // 1E/030 Reserved, MUST = 0 + + union { + + struct { + + BYTE CDBByte[6]; // 40/064 SCSI CDB + BYTE SenseArea[SENSE_LEN+2]; // 46/070 Request Sense buffer + + } PACKED _6; + + struct { + + BYTE CDBByte[10]; // 40/064 SCSI CDB + BYTE SenseArea[SENSE_LEN+2]; // 4A/074 Request Sense buffer + + } PACKED _10; + + struct { + + BYTE CDBByte[12]; // 40/064 SCSI CDB + BYTE SenseArea[SENSE_LEN+2]; // 4C/076 Request Sense buffer + + } PACKED _12; + + } PACKED CmdLen; + + } PACKED ExecSCSICmd; + + struct { + + VOID FAR *SRBToAbort; // 08/008 Pointer to SRB to abort + + } PACKED Abort; + + struct { + BYTE Target; // 08/008 Target's SCSI ID + BYTE Lun; // 09/009 Target's LUN number + BYTE ResetRsvd1[14]; // 0A/010 Reserved, MUST = 0 + BYTE HaStat; // 18/024 Host Adapter Status + BYTE TargStat; // 19/025 Target Status + VOID FAR *PostProc; // 1A/026 Post routine + BYTE ResetRsvd2[34]; // 1E/030 Reserved, MUST = 0 + } Reset; + } PACKED Type; + +} PACKED SRB; + +#endif /* __ASPI16_H_ */ diff --git a/libusal/usal/aspi-win32.h b/libusal/usal/aspi-win32.h new file mode 100644 index 0000000..865befe --- /dev/null +++ b/libusal/usal/aspi-win32.h @@ -0,0 +1,208 @@ +/* + * 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. + * + */ + +#ifndef __ASPI_WIN32_H_ +#define __ASPI_WIN32_H_ + +#include <Windows.h> + +/*************************************************************************** + ** SCSI MISCELLANEOUS EQUATES + ***************************************************************************/ +#define SENSE_LEN 14 /* Default sense buffer length */ +#define SRB_DIR_SCSI 0x00 /* Direction determined by SCSI */ +#define SRB_POSTING 0x01 /* Enable ASPI posting */ +#define SRB_ENABLE_RESIDUAL_COUNT 0x04 /* Enable residual byte count */ + /* reporting */ +#define SRB_DIR_IN 0x08 /* Transfer from SCSI target to */ + /* host */ +#define SRB_DIR_OUT 0x10 /* Transfer from host to SCSI */ + /* target */ +#define SRB_EVENT_NOTIFY 0x40 /* Enable ASPI event notification */ +#define RESIDUAL_COUNT_SUPPORTED 0x02 /* Extended buffer flag */ +#define MAX_SRB_TIMEOUT 1080001u /* 30 hour maximum timeout in sec */ +#define DEFAULT_SRB_TIMEOUT 1080001u /* use max.timeout by default */ + +/*************************************************************************** + ** ASPI command definitions + ***************************************************************************/ +#define SC_HA_INQUIRY 0x00 /* Host adapter inquiry */ +#define SC_GET_DEV_TYPE 0x01 /* Get device type */ +#define SC_EXEC_SCSI_CMD 0x02 /* Execute SCSI command */ +#define SC_ABORT_SRB 0x03 /* Abort an SRB */ +#define SC_RESET_DEV 0x04 /* SCSI bus device reset */ +#define SC_SET_HA_PARMS 0x05 /* Set HA parameters */ +#define SC_GET_DISK_INFO 0x06 /* Get Disk */ +#define SC_RESCAN_SCSI_BUS 0x07 /* Rebuild SCSI device map */ +#define SC_GETSET_TIMEOUTS 0x08 /* Get/Set target timeouts */ + + +/*************************************************************************** + ** SRB Status + ***************************************************************************/ +#define SS_PENDING 0x00 /* SRB being processed */ +#define SS_COMP 0x01 /* SRB completed without error */ +#define SS_ABORTED 0x02 /* SRB aborted */ +#define SS_ABORT_FAIL 0x03 /* Unable to abort SRB */ +#define SS_ERR 0x04 /* SRB completed with error */ +#define SS_INVALID_CMD 0x80 /* Invalid ASPI command */ +#define SS_INVALID_HA 0x81 /* Invalid host adapter number */ +#define SS_NO_DEVICE 0x82 /* SCSI device not installed */ +#define SS_INVALID_SRB 0xE0 /* Invalid parameter set in SRB */ +#define SS_OLD_MANAGER 0xE1 /* ASPI manager doesn't support */ + /* windows */ +#define SS_BUFFER_ALIGN 0xE1 /* Buffer not aligned (replaces */ + /* SS_OLD_MANAGER in Win32) */ +#define SS_ILLEGAL_MODE 0xE2 /* Unsupported Windows mode */ +#define SS_NO_ASPI 0xE3 /* No ASPI managers */ +#define SS_FAILED_INIT 0xE4 /* ASPI for windows failed init */ +#define SS_ASPI_IS_BUSY 0xE5 /* No resources available to */ + /* execute command */ +#define SS_BUFFER_TO_BIG 0xE6 /* Buffer size too big to handle */ +#define SS_BUFFER_TOO_BIG 0xE6 /* Correct spelling of 'too' */ +#define SS_MISMATCHED_COMPONENTS 0xE7 /* The DLLs/EXEs of ASPI don't */ + /* version check */ +#define SS_NO_ADAPTERS 0xE8 /* No host adapters to manager */ +#define SS_INSUFFICIENT_RESOURCES 0xE9 /* Couldn't allocate resources */ + /* needed to init */ +#define SS_ASPI_IS_SHUTDOWN 0xEA /* Call came to ASPI after */ + /* PROCESS_DETACH */ +#define SS_BAD_INSTALL 0xEB /* The DLL or other components */ + /* are installed wrong */ + +/*************************************************************************** + ** Host Adapter Status + ***************************************************************************/ +#define HASTAT_OK 0x00 /* No error detected by HA */ +#define HASTAT_SEL_TO 0x11 /* Selection Timeout */ +#define HASTAT_DO_DU 0x12 /* Data overrun/data underrun */ +#define HASTAT_BUS_FREE 0x13 /* Unexpected bus free */ +#define HASTAT_PHASE_ERR 0x14 /* Target bus phase sequence */ +#define HASTAT_TIMEOUT 0x09 /* Timed out while SRB was */ + /* waiting to be processed */ +#define HASTAT_COMMAND_TIMEOUT 0x0B /* Adapter timed out while */ + /* processing SRB */ +#define HASTAT_MESSAGE_REJECT 0x0D /* While processing the SRB, the */ + /* adapter received a MESSAGE */ +#define HASTAT_BUS_RESET 0x0E /* A bus reset was detected */ +#define HASTAT_PARITY_ERROR 0x0F /* A parity error was detected */ +#define HASTAT_REQUEST_SENSE_FAILED 0x10 /* The adapter failed in issuing */ + + +/*************************************************************************** + ** SRB - HOST ADAPTER INQUIRIY - SC_HA_INQUIRY (0) + ***************************************************************************/ +typedef struct { + BYTE SRB_Cmd; /* 00/000 ASPI command code == SC_HA_INQUIRY */ + BYTE SRB_Status; /* 01/001 ASPI command status byte */ + BYTE SRB_HaId; /* 02/002 ASPI host adapter number */ + BYTE SRB_Flags; /* 03/003 ASPI request flags */ + DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */ + BYTE HA_Count; /* 08/008 Number of host adapters present */ + BYTE HA_SCSI_ID; /* 09/009 SCSI ID of host adapter */ + BYTE HA_ManagerId[16]; /* 0a/010 String describing the manager */ + BYTE HA_Identifier[16]; /* 1a/026 String describing the host adapter */ + BYTE HA_Unique[16]; /* 2a/042 Host Adapter Unique parameters */ + WORD HA_Rsvd1; /* 3a/058 Reserved, must = 0 */ +} PACKED SRB_HAInquiry, *PSRB_HAInquiry, FAR *LPSRB_HAInquiry; + + +/*************************************************************************** + ** SRB - GET DEVICE TYPE - SC_GET_DEV_TYPE (1) + ***************************************************************************/ +typedef struct +{ + BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_GET_DEV_TYPE */ + BYTE SRB_Status; /* 01/001 ASPI command status byte */ + BYTE SRB_HaId; /* 02/002 ASPI host adapter number */ + BYTE SRB_Flags; /* 03/003 Reserved, must = 0 */ + DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */ + BYTE SRB_Target; /* 08/008 Target's SCSI ID */ + BYTE SRB_Lun; /* 09/009 Target's LUN number */ + BYTE SRB_DeviceType; /* 0a/010 Target's peripheral device type */ + BYTE SRB_Rsvd1; /* 0b/011 Reserved, must = 0 */ +} PACKED SRB_GDEVBlock, *PSRB_GDEVBlock, FAR *LPSRB_GDEVBlock; + + +/*************************************************************************** + ** SRB - EXECUTE SCSI COMMAND - SC_EXEC_SCSI_CMD (2) + ***************************************************************************/ +typedef struct +{ + BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_EXEC_SCSI_CMD */ + BYTE SRB_Status; /* 01/001 ASPI command status byte */ + BYTE SRB_HaId; /* 02/002 ASPI host adapter number */ + BYTE SRB_Flags; /* 03/003 Reserved, must = 0 */ + DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */ + BYTE SRB_Target; /* 08/008 Target's SCSI ID */ + BYTE SRB_Lun; /* 09/009 Target's LUN */ + WORD SRB_Rsvd1; /* 0a/010 Reserved for alignment */ + DWORD SRB_BufLen; /* 0c/012 Data Allocation Length */ + BYTE FAR *SRB_BufPointer; /* 10/016 Data Buffer Pointer */ + BYTE SRB_SenseLen; /* 14/020 Sense Allocation Length */ + BYTE SRB_CDBLen; /* 15/021 CDB Length */ + BYTE SRB_HaStat; /* 16/022 Host Adapter Status */ + BYTE SRB_TargStat; /* 17/023 Target Status */ + VOID FAR *SRB_PostProc; /* 18/024 Post routine */ + BYTE SRB_Rsvd2[20]; /* 1c/028 Reserved, must = 0 */ + BYTE CDBByte[16]; /* 30/048 SCSI CDB */ + BYTE SenseArea[SENSE_LEN+2]; /* 40/064 Request Sense buffer */ +} PACKED SRB_ExecSCSICmd, *PSRB_ExecSCSICmd, FAR *LPSRB_ExecSCSICmd; + + +typedef struct +{ + BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_ABORT_SRB */ + BYTE SRB_Status; /* 01/001 ASPI command status byte */ + BYTE SRB_HaId; /* 02/002 ASPI host adapter number */ + BYTE SRB_Flags; /* 03/003 Reserved, must = 0 */ + DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */ + void *SRB_ToAbort; /* 08/008 Pointer to SRB to abort */ +} PACKED SRB_Abort, *PSRB_Abort, FAR *LPSRB_Abort; + + +/*************************************************************************** + ** SRB - BUS DEVICE RESET - SC_RESET_DEV (4) + ***************************************************************************/ +typedef struct +{ + BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_RESET_DEV */ + BYTE SRB_Status; /* 01/001 ASPI command status byte */ + BYTE SRB_HaId; /* 02/002 ASPI host adapter number */ + DWORD SRB_Flags; /* 04/004 Reserved */ + BYTE SRB_Target; /* 08/008 Target's SCSI ID */ + BYTE SRB_Lun; /* 09/009 Target's LUN number */ + BYTE SRB_Rsvd1[12]; /* 0A/010 Reserved for alignment */ + BYTE SRB_HaStat; /* 16/022 Host Adapter Status */ + BYTE SRB_TargStat; /* 17/023 Target Status */ + VOID FAR *SRB_PostProc; /* 18/024 Post routine */ + BYTE SRB_Rsvd2[36]; /* 1C/028 Reserved, must = 0 */ +} SRB_BusDeviceReset, *PSRB_BusDeviceReset, FAR *LPSRB_BusDeviceReset; + +typedef struct tag_ASPI32BUFF +{ + PBYTE AB_BufPointer; + DWORD AB_BufLen; + DWORD AB_ZeroFill; + DWORD AB_Reserved; +} PACKED ASPI32BUFF, *PASPI32BUFF, FAR *LPASPI32BUFF; + +typedef struct +{ + BYTE SRB_Cmd; + BYTE SRB_Status; + BYTE SRB_HaId; + BYTE SRB_Flags; + DWORD SRB_Hdr_Rsvd; +} SRB, *PSRB, FAR *LPSRB; + +#endif diff --git a/libusal/usal/scsicdb.h b/libusal/usal/scsicdb.h new file mode 100644 index 0000000..2594776 --- /dev/null +++ b/libusal/usal/scsicdb.h @@ -0,0 +1,260 @@ +/* + * 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. + * + */ + +/* @(#)scsicdb.h 2.19 04/09/04 Copyright 1986 J. Schilling */ +/* + * Definitions for the SCSI Command Descriptor Block + * + * Copyright (c) 1986 J. Schilling + */ +/* + * 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. + */ + +#ifndef _SCG_SCSICDB_H +#define _SCG_SCSICDB_H + +#ifndef _UTYPES_H +#include <utypes.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif +/* + * SCSI Operation codes. + */ +#define SC_TEST_UNIT_READY 0x00 +#define SC_REZERO_UNIT 0x01 +#define SC_REQUEST_SENSE 0x03 +#define SC_FORMAT 0x04 +#define SC_FORMAT_TRACK 0x06 +#define SC_REASSIGN_BLOCK 0x07 /* CCS only */ +#define SC_SEEK 0x0b +#define SC_TRANSLATE 0x0f /* ACB4000 only */ +#define SC_INQUIRY 0x12 /* CCS only */ +#define SC_MODE_SELECT 0x15 +#define SC_RESERVE 0x16 +#define SC_RELEASE 0x17 +#define SC_MODE_SENSE 0x1a +#define SC_START 0x1b +#define SC_READ_DEFECT_LIST 0x37 /* CCS only, group 1 */ +#define SC_READ_BUFFER 0x3c /* CCS only, group 1 */ + /* + * Note, these two commands use identical command blocks for all + * controllers except the Adaptec ACB 4000 which sets bit 1 of byte 1. + */ +#define SC_READ 0x08 +#define SC_WRITE 0x0a +#define SC_EREAD 0x28 /* 10 byte read */ +#define SC_EWRITE 0x2a /* 10 byte write */ +#define SC_WRITE_VERIFY 0x2e /* 10 byte write+verify */ +#define SC_WRITE_FILE_MARK 0x10 +#define SC_UNKNOWN 0xff /* cmd list terminator */ + + +/* + * Standard SCSI control blocks. + * These go in or out over the SCSI bus. + */ + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_g0cdb { /* scsi group 0 command description block */ + Uchar cmd; /* command code */ + Ucbit high_addr : 5; /* high part of block address */ + Ucbit lun : 3; /* logical unit number */ + Uchar mid_addr; /* middle part of block address */ + Uchar low_addr; /* low part of block address */ + Uchar count; /* transfer length */ + Ucbit link : 1; /* link (another command follows) */ + Ucbit fr : 1; /* flag request (interrupt at completion) */ + Ucbit naca : 1; /* Normal ACA (Auto Contingent Allegiance) */ + Ucbit rsvd : 3; /* reserved */ + Ucbit vu_56 : 1; /* vendor unique (byte 5 bit 6) */ + Ucbit vu_57 : 1; /* vendor unique (byte 5 bit 7) */ +}; + +#else /* Motorola byteorder */ + +struct scsi_g0cdb { /* scsi group 0 command description block */ + Uchar cmd; /* command code */ + Ucbit lun : 3; /* logical unit number */ + Ucbit high_addr : 5; /* high part of block address */ + Uchar mid_addr; /* middle part of block address */ + Uchar low_addr; /* low part of block address */ + Uchar count; /* transfer length */ + Ucbit vu_57 : 1; /* vendor unique (byte 5 bit 7) */ + Ucbit vu_56 : 1; /* vendor unique (byte 5 bit 6) */ + Ucbit rsvd : 3; /* reserved */ + Ucbit naca : 1; /* Normal ACA (Auto Contingent Allegiance) */ + Ucbit fr : 1; /* flag request (interrupt at completion) */ + Ucbit link : 1; /* link (another command follows) */ +}; +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_g1cdb { /* scsi group 1 command description block */ + Uchar cmd; /* command code */ + Ucbit reladr : 1; /* address is relative */ + Ucbit res : 4; /* reserved bits 1-4 of byte 1 */ + Ucbit lun : 3; /* logical unit number */ + Uchar addr[4]; /* logical block address */ + Uchar res6; /* reserved byte 6 */ + Uchar count[2]; /* transfer length */ + Ucbit link : 1; /* link (another command follows) */ + Ucbit fr : 1; /* flag request (interrupt at completion) */ + Ucbit naca : 1; /* Normal ACA (Auto Contingent Allegiance) */ + Ucbit rsvd : 3; /* reserved */ + Ucbit vu_96 : 1; /* vendor unique (byte 5 bit 6) */ + Ucbit vu_97 : 1; /* vendor unique (byte 5 bit 7) */ +}; + +#else /* Motorola byteorder */ + +struct scsi_g1cdb { /* scsi group 1 command description block */ + Uchar cmd; /* command code */ + Ucbit lun : 3; /* logical unit number */ + Ucbit res : 4; /* reserved bits 1-4 of byte 1 */ + Ucbit reladr : 1; /* address is relative */ + Uchar addr[4]; /* logical block address */ + Uchar res6; /* reserved byte 6 */ + Uchar count[2]; /* transfer length */ + Ucbit vu_97 : 1; /* vendor unique (byte 5 bit 7) */ + Ucbit vu_96 : 1; /* vendor unique (byte 5 bit 6) */ + Ucbit rsvd : 3; /* reserved */ + Ucbit naca : 1; /* Normal ACA (Auto Contingent Allegiance) */ + Ucbit fr : 1; /* flag request (interrupt at completion) */ + Ucbit link : 1; /* link (another command follows) */ +}; +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_g5cdb { /* scsi group 5 command description block */ + Uchar cmd; /* command code */ + Ucbit reladr : 1; /* address is relative */ + Ucbit res : 4; /* reserved bits 1-4 of byte 1 */ + Ucbit lun : 3; /* logical unit number */ + Uchar addr[4]; /* logical block address */ + Uchar count[4]; /* transfer length */ + Uchar res10; /* reserved byte 10 */ + Ucbit link : 1; /* link (another command follows) */ + Ucbit fr : 1; /* flag request (interrupt at completion) */ + Ucbit naca : 1; /* Normal ACA (Auto Contingent Allegiance) */ + Ucbit rsvd : 3; /* reserved */ + Ucbit vu_B6 : 1; /* vendor unique (byte B bit 6) */ + Ucbit vu_B7 : 1; /* vendor unique (byte B bit 7) */ +}; + +#else /* Motorola byteorder */ + +struct scsi_g5cdb { /* scsi group 5 command description block */ + Uchar cmd; /* command code */ + Ucbit lun : 3; /* logical unit number */ + Ucbit res : 4; /* reserved bits 1-4 of byte 1 */ + Ucbit reladr : 1; /* address is relative */ + Uchar addr[4]; /* logical block address */ + Uchar count[4]; /* transfer length */ + Uchar res10; /* reserved byte 10 */ + Ucbit vu_B7 : 1; /* vendor unique (byte B bit 7) */ + Ucbit vu_B6 : 1; /* vendor unique (byte B bit 6) */ + Ucbit rsvd : 3; /* reserved */ + Ucbit naca : 1; /* Normal ACA (Auto Contingent Allegiance) */ + Ucbit fr : 1; /* flag request (interrupt at completion) */ + Ucbit link : 1; /* link (another command follows) */ +}; +#endif + +#define g0_cdbaddr(cdb, a) ((cdb)->high_addr = (a) >> 16,\ + (cdb)->mid_addr = ((a) >> 8) & 0xFF,\ + (cdb)->low_addr = (a) & 0xFF) + +#define g1_cdbaddr(cdb, a) ((cdb)->addr[0] = (a) >> 24,\ + (cdb)->addr[1] = ((a) >> 16)& 0xFF,\ + (cdb)->addr[2] = ((a) >> 8) & 0xFF,\ + (cdb)->addr[3] = (a) & 0xFF) + +#define g5_cdbaddr(cdb, a) g1_cdbaddr(cdb, a) + + +#define g0_cdblen(cdb, len) ((cdb)->count = (len)) + +#define g1_cdblen(cdb, len) ((cdb)->count[0] = ((len) >> 8) & 0xFF,\ + (cdb)->count[1] = (len) & 0xFF) + +#define g5_cdblen(cdb, len) ((cdb)->count[0] = (len) >> 24L,\ + (cdb)->count[1] = ((len) >> 16L)& 0xFF,\ + (cdb)->count[2] = ((len) >> 8L) & 0xFF,\ + (cdb)->count[3] = (len) & 0xFF) + +/*#define XXXXX*/ +#ifdef XXXXX +#define i_to_long(a, i) (((Uchar *)(a))[0] = ((i) >> 24)& 0xFF,\ + ((Uchar *)(a))[1] = ((i) >> 16)& 0xFF,\ + ((Uchar *)(a))[2] = ((i) >> 8) & 0xFF,\ + ((Uchar *)(a))[3] = (i) & 0xFF) + +#define i_to_3_byte(a, i) (((Uchar *)(a))[0] = ((i) >> 16)& 0xFF,\ + ((Uchar *)(a))[1] = ((i) >> 8) & 0xFF,\ + ((Uchar *)(a))[2] = (i) & 0xFF) + +#define i_to_4_byte(a, i) (((Uchar *)(a))[0] = ((i) >> 24)& 0xFF,\ + ((Uchar *)(a))[1] = ((i) >> 16)& 0xFF,\ + ((Uchar *)(a))[2] = ((i) >> 8) & 0xFF,\ + ((Uchar *)(a))[3] = (i) & 0xFF) + +#define i_to_short(a, i) (((Uchar *)(a))[0] = ((i) >> 8) & 0xFF,\ + ((Uchar *)(a))[1] = (i) & 0xFF) + +#define a_to_u_short(a) ((unsigned short) \ + ((((Uchar*) a)[1] & 0xFF) | \ + (((Uchar*) a)[0] << 8 & 0xFF00))) + +#define a_to_3_byte(a) ((Ulong) \ + ((((Uchar*) a)[2] & 0xFF) | \ + (((Uchar*) a)[1] << 8 & 0xFF00) | \ + (((Uchar*) a)[0] << 16 & 0xFF0000))) + +#ifdef __STDC__ +#define a_to_u_long(a) ((Ulong) \ + ((((Uchar*) a)[3] & 0xFF) | \ + (((Uchar*) a)[2] << 8 & 0xFF00) | \ + (((Uchar*) a)[1] << 16 & 0xFF0000) | \ + (((Uchar*) a)[0] << 24 & 0xFF000000UL))) +#else +#define a_to_u_long(a) ((Ulong) \ + ((((Uchar*) a)[3] & 0xFF) | \ + (((Uchar*) a)[2] << 8 & 0xFF00) | \ + (((Uchar*) a)[1] << 16 & 0xFF0000) | \ + (((Uchar*) a)[0] << 24 & 0xFF000000))) +#endif +#endif /* XXXX */ + + +#ifdef __cplusplus +} +#endif + +#endif /* _SCG_SCSICDB_H */ diff --git a/libusal/usal/scsidefs.h b/libusal/usal/scsidefs.h new file mode 100644 index 0000000..fc57c16 --- /dev/null +++ b/libusal/usal/scsidefs.h @@ -0,0 +1,136 @@ +/* + * 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. + * + */ + +/* @(#)scsidefs.h 1.28 04/09/04 Copyright 1988 J. Schilling */ +/* + * Definitions for SCSI devices i.e. for error strings in scsierrs.c + * + * Copyright (c) 1988 J. Schilling + */ +/* + * 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. + */ + +#ifndef _SCG_SCSIDEFS_H +#define _SCG_SCSIDEFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Disks + */ +#ifdef DEV_UNKNOWN +/* + * True64 defines DEV_UNKNOWN in /usr/include/sys/devio.h as "UNKNOWN" + */ +#undef DEV_UNKNOWN +#endif +#define DEV_UNKNOWN 0 +#define DEV_ACB40X0 1 +#define DEV_ACB4000 2 +#define DEV_ACB4010 3 +#define DEV_ACB4070 4 +#define DEV_ACB5500 5 +#define DEV_ACB4520A 6 +#define DEV_ACB4525 7 +#define DEV_MD21 8 +#define DEV_MD23 9 +#define DEV_NON_CCS_DSK 10 +#define DEV_CCS_GENDISK 11 + +/* + * Tapes + */ +#define DEV_MT02 100 +#define DEV_SC4000 101 + +/* + * Printer + */ +#define DEV_PRT 200 + +/* + * Processors + */ +#define DEV_PROC 300 + +/* + * Worm + */ +#define DEV_WORM 400 +#define DEV_RXT800S 401 + +/* + * CD-ROM + */ +#define DEV_CDROM 500 +#define DEV_MMC_CDROM 501 +#define DEV_MMC_CDR 502 +#define DEV_MMC_CDRW 503 +#define DEV_MMC_DVD 504 +#define DEV_MMC_DVD_WR 505 + +#define DEV_CDD_521_OLD 510 +#define DEV_CDD_521 511 +#define DEV_CDD_522 512 +#define DEV_PCD_600 513 +#define DEV_CDD_2000 514 +#define DEV_CDD_2600 515 +#define DEV_TYUDEN_EW50 516 +#define DEV_YAMAHA_CDR_100 520 +#define DEV_YAMAHA_CDR_400 521 +#define DEV_PLASMON_RF_4100 530 +#define DEV_SONY_CDU_924 540 +#define DEV_RICOH_RO_1420C 550 +#define DEV_RICOH_RO_1060C 551 +#define DEV_TEAC_CD_R50S 560 +#define DEV_MATSUSHITA_7501 570 +#define DEV_MATSUSHITA_7502 571 +#define DEV_PIONEER_DW_S114X 580 +#define DEV_PIONEER_DVDR_S101 581 + +/* + * Scanners + */ +#define DEV_HRSCAN 600 +#define DEV_MS300A 601 + +/* + * Optical memory + */ +#define DEV_SONY_SMO 700 + + +#define old_acb(d) (((d) == DEV_ACB40X0) || \ + ((d) == DEV_ACB4000) || ((d) == DEV_ACB4010) || \ + ((d) == DEV_ACB4070) || ((d) == DEV_ACB5500)) + +#define is_ccs(d) (!old_acb(d)) + +#ifdef __cplusplus +} +#endif + +#endif /* _SCG_SCSIDEFS_H */ diff --git a/libusal/usal/scsireg.h b/libusal/usal/scsireg.h new file mode 100644 index 0000000..9fc0ea3 --- /dev/null +++ b/libusal/usal/scsireg.h @@ -0,0 +1,1240 @@ +/* + * 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. + * + */ + +/* @(#)scsireg.h 1.31 04/09/04 Copyright 1987 J. Schilling */ +/* + * usefull definitions for dealing with CCS SCSI - devices + * + * Copyright (c) 1987 J. Schilling + */ +/* + * 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. + */ + +#ifndef _SCG_SCSIREG_H +#define _SCG_SCSIREG_H + +#include <utypes.h> +#include <btorder.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_inquiry { + Ucbit type : 5; /* 0 */ + Ucbit qualifier : 3; /* 0 */ + + Ucbit type_modifier : 7; /* 1 */ + Ucbit removable : 1; /* 1 */ + + Ucbit ansi_version : 3; /* 2 */ + Ucbit ecma_version : 3; /* 2 */ + Ucbit iso_version : 2; /* 2 */ + + Ucbit data_format : 4; /* 3 */ + Ucbit res3_54 : 2; /* 3 */ + Ucbit termiop : 1; /* 3 */ + Ucbit aenc : 1; /* 3 */ + + Ucbit add_len : 8; /* 4 */ + Ucbit sense_len : 8; /* 5 */ /* only Emulex ??? */ + Ucbit res2 : 8; /* 6 */ + + Ucbit softreset : 1; /* 7 */ + Ucbit cmdque : 1; + Ucbit res7_2 : 1; + Ucbit linked : 1; + Ucbit sync : 1; + Ucbit wbus16 : 1; + Ucbit wbus32 : 1; + Ucbit reladr : 1; /* 7 */ + + char vendor_info[8]; /* 8 */ + char prod_ident[16]; /* 16 */ + char prod_revision[4]; /* 32 */ +#ifdef comment + char vendor_uniq[20]; /* 36 */ + char reserved[40]; /* 56 */ +#endif +}; /* 96 */ + +#else /* Motorola byteorder */ + +struct scsi_inquiry { + Ucbit qualifier : 3; /* 0 */ + Ucbit type : 5; /* 0 */ + + Ucbit removable : 1; /* 1 */ + Ucbit type_modifier : 7; /* 1 */ + + Ucbit iso_version : 2; /* 2 */ + Ucbit ecma_version : 3; + Ucbit ansi_version : 3; /* 2 */ + + Ucbit aenc : 1; /* 3 */ + Ucbit termiop : 1; + Ucbit res3_54 : 2; + Ucbit data_format : 4; /* 3 */ + + Ucbit add_len : 8; /* 4 */ + Ucbit sense_len : 8; /* 5 */ /* only Emulex ??? */ + Ucbit res2 : 8; /* 6 */ + Ucbit reladr : 1; /* 7 */ + Ucbit wbus32 : 1; + Ucbit wbus16 : 1; + Ucbit sync : 1; + Ucbit linked : 1; + Ucbit res7_2 : 1; + Ucbit cmdque : 1; + Ucbit softreset : 1; + char vendor_info[8]; /* 8 */ + char prod_ident[16]; /* 16 */ + char prod_revision[4]; /* 32 */ +#ifdef comment + char vendor_uniq[20]; /* 36 */ + char reserved[40]; /* 56 */ +#endif +}; /* 96 */ +#endif + +#ifdef __SCG_COMPAT__ +#define info vendor_info +#define ident prod_ident +#define revision prod_revision +#endif + +/* Peripheral Device Qualifier */ + +#define INQ_DEV_PRESENT 0x00 /* Physical device present */ +#define INQ_DEV_NOTPR 0x01 /* Physical device not present */ +#define INQ_DEV_RES 0x02 /* Reserved */ +#define INQ_DEV_NOTSUP 0x03 /* Logical unit not supported */ + +/* Peripheral Device Type */ + +#define INQ_DASD 0x00 /* Direct-access device (disk) */ +#define INQ_SEQD 0x01 /* Sequential-access device (tape) */ +#define INQ_PRTD 0x02 /* Printer device */ +#define INQ_PROCD 0x03 /* Processor device */ +#define INQ_OPTD 0x04 /* Write once device (optical disk) */ +#define INQ_WORM 0x04 /* Write once device (optical disk) */ +#define INQ_ROMD 0x05 /* CD-ROM device */ +#define INQ_SCAN 0x06 /* Scanner device */ +#define INQ_OMEM 0x07 /* Optical Memory device */ +#define INQ_JUKE 0x08 /* Medium Changer device (jukebox) */ +#define INQ_COMM 0x09 /* Communications device */ +#define INQ_IT8_1 0x0A /* IT8 */ +#define INQ_IT8_2 0x0B /* IT8 */ +#define INQ_STARR 0x0C /* Storage array device */ +#define INQ_ENCL 0x0D /* Enclosure services device */ +#define INQ_SDAD 0x0E /* Simplyfied direct-access device */ +#define INQ_OCRW 0x0F /* Optical card reader/writer device */ +#define INQ_BRIDGE 0x10 /* Bridging expander device */ +#define INQ_OSD 0x11 /* Object based storage device */ +#define INQ_ADC 0x12 /* Automation/Drive interface */ +#define INQ_WELLKNOWN 0x1E /* Well known logical unit */ +#define INQ_NODEV 0x1F /* Unknown or no device */ +#define INQ_NOTPR 0x1F /* Logical unit not present (SCSI-1) */ + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_mode_header { + Ucbit sense_data_len : 8; + Uchar medium_type; + Ucbit res2 : 4; + Ucbit cache : 1; + Ucbit res : 2; + Ucbit write_prot : 1; + Uchar blockdesc_len; +}; + +#else /* Motorola byteorder */ + +struct scsi_mode_header { + Ucbit sense_data_len : 8; + Uchar medium_type; + Ucbit write_prot : 1; + Ucbit res : 2; + Ucbit cache : 1; + Ucbit res2 : 4; + Uchar blockdesc_len; +}; +#endif + +struct scsi_modesel_header { + Ucbit sense_data_len : 8; + Uchar medium_type; + Ucbit res2 : 8; + Uchar blockdesc_len; +}; + +struct scsi_mode_blockdesc { + Uchar density; + Uchar nlblock[3]; + Ucbit res : 8; + Uchar lblen[3]; +}; + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct acb_mode_data { + Uchar listformat; + Uchar ncyl[2]; + Uchar nhead; + Uchar start_red_wcurrent[2]; + Uchar start_precomp[2]; + Uchar landing_zone; + Uchar step_rate; + Ucbit : 2; + Ucbit hard_sec : 1; + Ucbit fixed_media : 1; + Ucbit : 4; + Uchar sect_per_trk; +}; + +#else /* Motorola byteorder */ + +struct acb_mode_data { + Uchar listformat; + Uchar ncyl[2]; + Uchar nhead; + Uchar start_red_wcurrent[2]; + Uchar start_precomp[2]; + Uchar landing_zone; + Uchar step_rate; + Ucbit : 4; + Ucbit fixed_media : 1; + Ucbit hard_sec : 1; + Ucbit : 2; + Uchar sect_per_trk; +}; +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_mode_page_header { + Ucbit p_code : 6; + Ucbit res : 1; + Ucbit parsave : 1; + Uchar p_len; +}; + +/* + * This is a hack that allows mode pages without + * any further bitfileds to be defined bitorder independent. + */ +#define MP_P_CODE \ + Ucbit p_code : 6; \ + Ucbit p_res : 1; \ + Ucbit parsave : 1 + +#else /* Motorola byteorder */ + +struct scsi_mode_page_header { + Ucbit parsave : 1; + Ucbit res : 1; + Ucbit p_code : 6; + Uchar p_len; +}; + +/* + * This is a hack that allows mode pages without + * any further bitfileds to be defined bitorder independent. + */ +#define MP_P_CODE \ + Ucbit parsave : 1; \ + Ucbit p_res : 1; \ + Ucbit p_code : 6 + +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_mode_page_01 { /* Error recovery Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x0A = 12 Bytes */ + Ucbit disa_correction : 1; /* Byte 2 */ + Ucbit term_on_rec_err : 1; + Ucbit report_rec_err : 1; + Ucbit en_early_corr : 1; + Ucbit read_continuous : 1; + Ucbit tranfer_block : 1; + Ucbit en_auto_reall_r : 1; + Ucbit en_auto_reall_w : 1; /* Byte 2 */ + Uchar rd_retry_count; /* Byte 3 */ + Uchar correction_span; + char head_offset_count; + char data_strobe_offset; + Uchar res; + Uchar wr_retry_count; + Uchar res_tape[2]; + Uchar recov_timelim[2]; +}; + +#else /* Motorola byteorder */ + +struct scsi_mode_page_01 { /* Error recovery Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x0A = 12 Bytes */ + Ucbit en_auto_reall_w : 1; /* Byte 2 */ + Ucbit en_auto_reall_r : 1; + Ucbit tranfer_block : 1; + Ucbit read_continuous : 1; + Ucbit en_early_corr : 1; + Ucbit report_rec_err : 1; + Ucbit term_on_rec_err : 1; + Ucbit disa_correction : 1; /* Byte 2 */ + Uchar rd_retry_count; /* Byte 3 */ + Uchar correction_span; + char head_offset_count; + char data_strobe_offset; + Uchar res; + Uchar wr_retry_count; + Uchar res_tape[2]; + Uchar recov_timelim[2]; +}; +#endif + + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_mode_page_02 { /* Device dis/re connect Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x0E = 16 Bytes */ + Uchar buf_full_ratio; + Uchar buf_empt_ratio; + Uchar bus_inact_limit[2]; + Uchar disc_time_limit[2]; + Uchar conn_time_limit[2]; + Uchar max_burst_size[2]; /* Start SCSI-2 */ + Ucbit data_tr_dis_ctl : 2; + Ucbit : 6; + Uchar res[3]; +}; + +#else /* Motorola byteorder */ + +struct scsi_mode_page_02 { /* Device dis/re connect Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x0E = 16 Bytes */ + Uchar buf_full_ratio; + Uchar buf_empt_ratio; + Uchar bus_inact_limit[2]; + Uchar disc_time_limit[2]; + Uchar conn_time_limit[2]; + Uchar max_burst_size[2]; /* Start SCSI-2 */ + Ucbit : 6; + Ucbit data_tr_dis_ctl : 2; + Uchar res[3]; +}; +#endif + +#define DTDC_DATADONE 0x01 /* + * Target may not disconnect once + * data transfer is started until + * all data successfully transferred. + */ + +#define DTDC_CMDDONE 0x03 /* + * Target may not disconnect once + * data transfer is started until + * command completed. + */ + + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_mode_page_03 { /* Direct access format Paramters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x16 = 24 Bytes */ + Uchar trk_per_zone[2]; + Uchar alt_sec_per_zone[2]; + Uchar alt_trk_per_zone[2]; + Uchar alt_trk_per_vol[2]; + Uchar sect_per_trk[2]; + Uchar bytes_per_phys_sect[2]; + Uchar interleave[2]; + Uchar trk_skew[2]; + Uchar cyl_skew[2]; + Ucbit : 3; + Ucbit inhibit_save : 1; + Ucbit fmt_by_surface : 1; + Ucbit removable : 1; + Ucbit hard_sec : 1; + Ucbit soft_sec : 1; + Uchar res[3]; +}; + +#else /* Motorola byteorder */ + +struct scsi_mode_page_03 { /* Direct access format Paramters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x16 = 24 Bytes */ + Uchar trk_per_zone[2]; + Uchar alt_sec_per_zone[2]; + Uchar alt_trk_per_zone[2]; + Uchar alt_trk_per_vol[2]; + Uchar sect_per_trk[2]; + Uchar bytes_per_phys_sect[2]; + Uchar interleave[2]; + Uchar trk_skew[2]; + Uchar cyl_skew[2]; + Ucbit soft_sec : 1; + Ucbit hard_sec : 1; + Ucbit removable : 1; + Ucbit fmt_by_surface : 1; + Ucbit inhibit_save : 1; + Ucbit : 3; + Uchar res[3]; +}; +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_mode_page_04 { /* Rigid disk Geometry Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x16 = 24 Bytes */ + Uchar ncyl[3]; + Uchar nhead; + Uchar start_precomp[3]; + Uchar start_red_wcurrent[3]; + Uchar step_rate[2]; + Uchar landing_zone[3]; + Ucbit rot_pos_locking : 2; /* Start SCSI-2 */ + Ucbit : 6; /* Start SCSI-2 */ + Uchar rotational_off; + Uchar res1; + Uchar rotation_rate[2]; + Uchar res2[2]; +}; + +#else /* Motorola byteorder */ + +struct scsi_mode_page_04 { /* Rigid disk Geometry Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x16 = 24 Bytes */ + Uchar ncyl[3]; + Uchar nhead; + Uchar start_precomp[3]; + Uchar start_red_wcurrent[3]; + Uchar step_rate[2]; + Uchar landing_zone[3]; + Ucbit : 6; /* Start SCSI-2 */ + Ucbit rot_pos_locking : 2; /* Start SCSI-2 */ + Uchar rotational_off; + Uchar res1; + Uchar rotation_rate[2]; + Uchar res2[2]; +}; +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_mode_page_05 { /* Flexible disk Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x1E = 32 Bytes */ + Uchar transfer_rate[2]; + Uchar nhead; + Uchar sect_per_trk; + Uchar bytes_per_phys_sect[2]; + Uchar ncyl[2]; + Uchar start_precomp[2]; + Uchar start_red_wcurrent[2]; + Uchar step_rate[2]; + Uchar step_pulse_width; + Uchar head_settle_delay[2]; + Uchar motor_on_delay; + Uchar motor_off_delay; + Ucbit spc : 4; + Ucbit : 4; + Ucbit : 5; + Ucbit mo : 1; + Ucbit ssn : 1; + Ucbit trdy : 1; + Uchar write_compensation; + Uchar head_load_delay; + Uchar head_unload_delay; + Ucbit pin_2_use : 4; + Ucbit pin_34_use : 4; + Ucbit pin_1_use : 4; + Ucbit pin_4_use : 4; + Uchar rotation_rate[2]; + Uchar res[2]; +}; + +#else /* Motorola byteorder */ + +struct scsi_mode_page_05 { /* Flexible disk Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x1E = 32 Bytes */ + Uchar transfer_rate[2]; + Uchar nhead; + Uchar sect_per_trk; + Uchar bytes_per_phys_sect[2]; + Uchar ncyl[2]; + Uchar start_precomp[2]; + Uchar start_red_wcurrent[2]; + Uchar step_rate[2]; + Uchar step_pulse_width; + Uchar head_settle_delay[2]; + Uchar motor_on_delay; + Uchar motor_off_delay; + Ucbit trdy : 1; + Ucbit ssn : 1; + Ucbit mo : 1; + Ucbit : 5; + Ucbit : 4; + Ucbit spc : 4; + Uchar write_compensation; + Uchar head_load_delay; + Uchar head_unload_delay; + Ucbit pin_34_use : 4; + Ucbit pin_2_use : 4; + Ucbit pin_4_use : 4; + Ucbit pin_1_use : 4; + Uchar rotation_rate[2]; + Uchar res[2]; +}; +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_mode_page_07 { /* Verify Error recovery */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x0A = 12 Bytes */ + Ucbit disa_correction : 1; /* Byte 2 */ + Ucbit term_on_rec_err : 1; + Ucbit report_rec_err : 1; + Ucbit en_early_corr : 1; + Ucbit res : 4; /* Byte 2 */ + Uchar ve_retry_count; /* Byte 3 */ + Uchar ve_correction_span; + char res2[5]; /* Byte 5 */ + Uchar ve_recov_timelim[2]; /* Byte 10 */ +}; + +#else /* Motorola byteorder */ + +struct scsi_mode_page_07 { /* Verify Error recovery */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x0A = 12 Bytes */ + Ucbit res : 4; /* Byte 2 */ + Ucbit en_early_corr : 1; + Ucbit report_rec_err : 1; + Ucbit term_on_rec_err : 1; + Ucbit disa_correction : 1; /* Byte 2 */ + Uchar ve_retry_count; /* Byte 3 */ + Uchar ve_correction_span; + char res2[5]; /* Byte 5 */ + Uchar ve_recov_timelim[2]; /* Byte 10 */ +}; +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_mode_page_08 { /* Caching Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x0A = 12 Bytes */ + Ucbit disa_rd_cache : 1; /* Byte 2 */ + Ucbit muliple_fact : 1; + Ucbit en_wt_cache : 1; + Ucbit res : 5; /* Byte 2 */ + Ucbit wt_ret_pri : 4; /* Byte 3 */ + Ucbit demand_rd_ret_pri: 4; /* Byte 3 */ + Uchar disa_pref_tr_len[2]; /* Byte 4 */ + Uchar min_pref[2]; /* Byte 6 */ + Uchar max_pref[2]; /* Byte 8 */ + Uchar max_pref_ceiling[2]; /* Byte 10 */ +}; + +#else /* Motorola byteorder */ + +struct scsi_mode_page_08 { /* Caching Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x0A = 12 Bytes */ + Ucbit res : 5; /* Byte 2 */ + Ucbit en_wt_cache : 1; + Ucbit muliple_fact : 1; + Ucbit disa_rd_cache : 1; /* Byte 2 */ + Ucbit demand_rd_ret_pri: 4; /* Byte 3 */ + Ucbit wt_ret_pri : 4; + Uchar disa_pref_tr_len[2]; /* Byte 4 */ + Uchar min_pref[2]; /* Byte 6 */ + Uchar max_pref[2]; /* Byte 8 */ + Uchar max_pref_ceiling[2]; /* Byte 10 */ +}; +#endif + +struct scsi_mode_page_09 { /* Peripheral device Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* >= 0x06 = 8 Bytes */ + Uchar interface_id[2]; /* Byte 2 */ + Uchar res[4]; /* Byte 4 */ + Uchar vendor_specific[1]; /* Byte 8 */ +}; + +#define PDEV_SCSI 0x0000 /* scsi interface */ +#define PDEV_SMD 0x0001 /* SMD interface */ +#define PDEV_ESDI 0x0002 /* ESDI interface */ +#define PDEV_IPI2 0x0003 /* IPI-2 interface */ +#define PDEV_IPI3 0x0004 /* IPI-3 interface */ + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_mode_page_0A { /* Common device Control Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x06 = 8 Bytes */ + Ucbit rep_log_exeption: 1; /* Byte 2 */ + Ucbit res : 7; /* Byte 2 */ + Ucbit dis_queuing : 1; /* Byte 3 */ + Ucbit queuing_err_man : 1; + Ucbit res2 : 2; + Ucbit queue_alg_mod : 4; /* Byte 3 */ + Ucbit EAENP : 1; /* Byte 4 */ + Ucbit UAENP : 1; + Ucbit RAENP : 1; + Ucbit res3 : 4; + Ucbit en_ext_cont_all : 1; /* Byte 4 */ + Ucbit res4 : 8; + Uchar ready_aen_hold_per[2]; /* Byte 6 */ +}; + +#else /* Motorola byteorder */ + +struct scsi_mode_page_0A { /* Common device Control Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x06 = 8 Bytes */ + Ucbit res : 7; /* Byte 2 */ + Ucbit rep_log_exeption: 1; /* Byte 2 */ + Ucbit queue_alg_mod : 4; /* Byte 3 */ + Ucbit res2 : 2; + Ucbit queuing_err_man : 1; + Ucbit dis_queuing : 1; /* Byte 3 */ + Ucbit en_ext_cont_all : 1; /* Byte 4 */ + Ucbit res3 : 4; + Ucbit RAENP : 1; + Ucbit UAENP : 1; + Ucbit EAENP : 1; /* Byte 4 */ + Ucbit res4 : 8; + Uchar ready_aen_hold_per[2]; /* Byte 6 */ +}; +#endif + +#define CTRL_QMOD_RESTRICT 0x0 +#define CTRL_QMOD_UNRESTRICT 0x1 + + +struct scsi_mode_page_0B { /* Medium Types Supported Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x06 = 8 Bytes */ + Uchar res[2]; /* Byte 2 */ + Uchar medium_one_supp; /* Byte 4 */ + Uchar medium_two_supp; /* Byte 5 */ + Uchar medium_three_supp; /* Byte 6 */ + Uchar medium_four_supp; /* Byte 7 */ +}; + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_mode_page_0C { /* Notch & Partition Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x16 = 24 Bytes */ + Ucbit res : 6; /* Byte 2 */ + Ucbit logical_notch : 1; + Ucbit notched_drive : 1; /* Byte 2 */ + Uchar res2; /* Byte 3 */ + Uchar max_notches[2]; /* Byte 4 */ + Uchar active_notch[2]; /* Byte 6 */ + Uchar starting_boundary[4]; /* Byte 8 */ + Uchar ending_boundary[4]; /* Byte 12 */ + Uchar pages_notched[8]; /* Byte 16 */ +}; + +#else /* Motorola byteorder */ + +struct scsi_mode_page_0C { /* Notch & Partition Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x16 = 24 Bytes */ + Ucbit notched_drive : 1; /* Byte 2 */ + Ucbit logical_notch : 1; + Ucbit res : 6; /* Byte 2 */ + Uchar res2; /* Byte 3 */ + Uchar max_notches[2]; /* Byte 4 */ + Uchar active_notch[2]; /* Byte 6 */ + Uchar starting_boundary[4]; /* Byte 8 */ + Uchar ending_boundary[4]; /* Byte 12 */ + Uchar pages_notched[8]; /* Byte 16 */ +}; +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_mode_page_0D { /* CD-ROM Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x06 = 8 Bytes */ + Uchar res; /* Byte 2 */ + Ucbit inact_timer_mult: 4; /* Byte 3 */ + Ucbit res2 : 4; /* Byte 3 */ + Uchar s_un_per_m_un[2]; /* Byte 4 */ + Uchar f_un_per_s_un[2]; /* Byte 6 */ +}; + +#else /* Motorola byteorder */ + +struct scsi_mode_page_0D { /* CD-ROM Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x06 = 8 Bytes */ + Uchar res; /* Byte 2 */ + Ucbit res2 : 4; /* Byte 3 */ + Ucbit inact_timer_mult: 4; /* Byte 3 */ + Uchar s_un_per_m_un[2]; /* Byte 4 */ + Uchar f_un_per_s_un[2]; /* Byte 6 */ +}; +#endif + +struct sony_mode_page_20 { /* Sony Format Mode Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x0A = 12 Bytes */ + Uchar format_mode; + Uchar format_type; +#define num_bands user_band_size /* Gilt bei Type 1 */ + Uchar user_band_size[4]; /* Gilt bei Type 0 */ + Uchar spare_band_size[2]; + Uchar res[2]; +}; + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct toshiba_mode_page_20 { /* Toshiba Speed Control Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x01 = 3 Bytes */ + Ucbit speed : 1; + Ucbit res : 7; +}; + +#else /* Motorola byteorder */ + +struct toshiba_mode_page_20 { /* Toshiba Speed Control Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x01 = 3 Bytes */ + Ucbit res : 7; + Ucbit speed : 1; +}; +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct ccs_mode_page_38 { /* CCS Caching Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x0E = 14 Bytes */ + + Ucbit cache_table_size: 4; /* Byte 3 */ + Ucbit cache_en : 1; + Ucbit res2 : 1; + Ucbit wr_index_en : 1; + Ucbit res : 1; /* Byte 3 */ + Uchar threshold; /* Byte 4 Prefetch threshold */ + Uchar max_prefetch; /* Byte 5 Max. prefetch */ + Uchar max_multiplier; /* Byte 6 Max. prefetch multiplier */ + Uchar min_prefetch; /* Byte 7 Min. prefetch */ + Uchar min_multiplier; /* Byte 8 Min. prefetch multiplier */ + Uchar res3[8]; /* Byte 9 */ +}; + +#else /* Motorola byteorder */ + +struct ccs_mode_page_38 { /* CCS Caching Parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x0E = 14 Bytes */ + + Ucbit res : 1; /* Byte 3 */ + Ucbit wr_index_en : 1; + Ucbit res2 : 1; + Ucbit cache_en : 1; + Ucbit cache_table_size: 4; /* Byte 3 */ + Uchar threshold; /* Byte 4 Prefetch threshold */ + Uchar max_prefetch; /* Byte 5 Max. prefetch */ + Uchar max_multiplier; /* Byte 6 Max. prefetch multiplier */ + Uchar min_prefetch; /* Byte 7 Min. prefetch */ + Uchar min_multiplier; /* Byte 8 Min. prefetch multiplier */ + Uchar res3[8]; /* Byte 9 */ +}; +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct cd_mode_page_05 { /* write parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x32 = 50 Bytes */ + Ucbit write_type : 4; /* Session write type (PACKET/TAO...)*/ + Ucbit test_write : 1; /* Do not actually write data */ + Ucbit LS_V : 1; /* Link size valid */ + Ucbit BUFE : 1; /* Enable Bufunderrun free rec. */ + Ucbit res_2_7 : 1; + Ucbit track_mode : 4; /* Track mode (Q-sub control nibble) */ + Ucbit copy : 1; /* 1st higher gen of copy prot track ~*/ + Ucbit fp : 1; /* Fixed packed (if in packet mode) */ + Ucbit multi_session : 2; /* Multi session write type */ + Ucbit dbtype : 4; /* Data block type */ + Ucbit res_4 : 4; /* Reserved */ + Uchar link_size; /* Link Size (default is 7) */ + Uchar res_6; /* Reserved */ + Ucbit host_appl_code : 6; /* Host application code of disk */ + Ucbit res_7 : 2; /* Reserved */ + Uchar session_format; /* Session format (DA/CDI/XA) */ + Uchar res_9; /* Reserved */ + Uchar packet_size[4]; /* # of user datablocks/fixed packet */ + Uchar audio_pause_len[2]; /* # of blocks where index is zero */ + Uchar media_cat_number[16]; /* Media catalog Number (MCN) */ + Uchar ISRC[14]; /* ISRC for this track */ + Uchar sub_header[4]; + Uchar vendor_uniq[4]; +}; + +#else /* Motorola byteorder */ + +struct cd_mode_page_05 { /* write parameters */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x32 = 50 Bytes */ + Ucbit res_2_7 : 1; + Ucbit BUFE : 1; /* Enable Bufunderrun free rec. */ + Ucbit LS_V : 1; /* Link size valid */ + Ucbit test_write : 1; /* Do not actually write data */ + Ucbit write_type : 4; /* Session write type (PACKET/TAO...)*/ + Ucbit multi_session : 2; /* Multi session write type */ + Ucbit fp : 1; /* Fixed packed (if in packet mode) */ + Ucbit copy : 1; /* 1st higher gen of copy prot track */ + Ucbit track_mode : 4; /* Track mode (Q-sub control nibble) */ + Ucbit res_4 : 4; /* Reserved */ + Ucbit dbtype : 4; /* Data block type */ + Uchar link_size; /* Link Size (default is 7) */ + Uchar res_6; /* Reserved */ + Ucbit res_7 : 2; /* Reserved */ + Ucbit host_appl_code : 6; /* Host application code of disk */ + Uchar session_format; /* Session format (DA/CDI/XA) */ + Uchar res_9; /* Reserved */ + Uchar packet_size[4]; /* # of user datablocks/fixed packet */ + Uchar audio_pause_len[2]; /* # of blocks where index is zero */ + Uchar media_cat_number[16]; /* Media catalog Number (MCN) */ + Uchar ISRC[14]; /* ISRC for this track */ + Uchar sub_header[4]; + Uchar vendor_uniq[4]; +}; + +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct cd_wr_speed_performance { + Uchar res0; /* Reserved */ + Ucbit rot_ctl_sel : 2; /* Rotational control selected */ + Ucbit res_1_27 : 6; /* Reserved */ + Uchar wr_speed_supp[2]; /* Supported write speed */ +}; + +struct cd_mode_page_2A { /* CD Cap / mech status */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x14 = 20 Bytes (MMC) */ + /* 0x18 = 24 Bytes (MMC-2) */ + /* 0x1C >= 28 Bytes (MMC-3) */ + Ucbit cd_r_read : 1; /* Reads CD-R media */ + Ucbit cd_rw_read : 1; /* Reads CD-RW media */ + Ucbit method2 : 1; /* Reads fixed packet method2 media */ + Ucbit dvd_rom_read : 1; /* Reads DVD ROM media */ + Ucbit dvd_r_read : 1; /* Reads DVD-R media */ + Ucbit dvd_ram_read : 1; /* Reads DVD-RAM media */ + Ucbit res_2_67 : 2; /* Reserved */ + Ucbit cd_r_write : 1; /* Supports writing CD-R media */ + Ucbit cd_rw_write : 1; /* Supports writing CD-RW media */ + Ucbit test_write : 1; /* Supports emulation write */ + Ucbit res_3_3 : 1; /* Reserved */ + Ucbit dvd_r_write : 1; /* Supports writing DVD-R media */ + Ucbit dvd_ram_write : 1; /* Supports writing DVD-RAM media */ + Ucbit res_3_67 : 2; /* Reserved */ + Ucbit audio_play : 1; /* Supports Audio play operation */ + Ucbit composite : 1; /* Deliveres composite A/V stream */ + Ucbit digital_port_2 : 1; /* Supports digital output on port 2 */ + Ucbit digital_port_1 : 1; /* Supports digital output on port 1 */ + Ucbit mode_2_form_1 : 1; /* Reads Mode-2 form 1 media (XA) */ + Ucbit mode_2_form_2 : 1; /* Reads Mode-2 form 2 media */ + Ucbit multi_session : 1; /* Reads multi-session media */ + Ucbit BUF : 1; /* Supports Buffer under. free rec. */ + Ucbit cd_da_supported : 1; /* Reads audio data with READ CD cmd */ + Ucbit cd_da_accurate : 1; /* READ CD data stream is accurate */ + Ucbit rw_supported : 1; /* Reads R-W sub channel information */ + Ucbit rw_deint_corr : 1; /* Reads de-interleved R-W sub chan */ + Ucbit c2_pointers : 1; /* Supports C2 error pointers */ + Ucbit ISRC : 1; /* Reads ISRC information */ + Ucbit UPC : 1; /* Reads media catalog number (UPC) */ + Ucbit read_bar_code : 1; /* Supports reading bar codes */ + Ucbit lock : 1; /* PREVENT/ALLOW may lock media */ + Ucbit lock_state : 1; /* Lock state 0=unlocked 1=locked */ + Ucbit prevent_jumper : 1; /* State of prev/allow jumper 0=pres */ + Ucbit eject : 1; /* Ejects disc/cartr with STOP LoEj */ + Ucbit res_6_4 : 1; /* Reserved */ + Ucbit loading_type : 3; /* Loading mechanism type */ + Ucbit sep_chan_vol : 1; /* Vol controls each channel separat */ + Ucbit sep_chan_mute : 1; /* Mute controls each channel separat*/ + Ucbit disk_present_rep: 1; /* Changer supports disk present rep */ + Ucbit sw_slot_sel : 1; /* Load empty slot in changer */ + Ucbit side_change : 1; /* Side change capable */ + Ucbit pw_in_lead_in : 1; /* Reads raw P-W sucode from lead in */ + Ucbit res_7 : 2; /* Reserved */ + Uchar max_read_speed[2]; /* Max. read speed in KB/s */ + Uchar num_vol_levels[2]; /* # of supported volume levels */ + Uchar buffer_size[2]; /* Buffer size for the data in KB */ + Uchar cur_read_speed[2]; /* Current read speed in KB/s */ + Uchar res_16; /* Reserved */ + Ucbit res_17_0 : 1; /* Reserved */ + Ucbit BCK : 1; /* Data valid on falling edge of BCK */ + Ucbit RCK : 1; /* Set: HIGH high LRCK=left channel */ + Ucbit LSBF : 1; /* Set: LSB first Clear: MSB first */ + Ucbit length : 2; /* 0=32BCKs 1=16BCKs 2=24BCKs 3=24I2c*/ + Ucbit res_17 : 2; /* Reserved */ + Uchar max_write_speed[2]; /* Max. write speed supported in KB/s*/ + Uchar cur_write_speed[2]; /* Current write speed in KB/s */ + + /* Byte 22 ... Only in MMC-2 */ + Uchar copy_man_rev[2]; /* Copy management revision supported*/ + Uchar res_24; /* Reserved */ + Uchar res_25; /* Reserved */ + + /* Byte 26 ... Only in MMC-3 */ + Uchar res_26; /* Reserved */ + Ucbit res_27_27 : 6; /* Reserved */ + Ucbit rot_ctl_sel : 2; /* Rotational control selected */ + Uchar v3_cur_write_speed[2]; /* Current write speed in KB/s */ + Uchar num_wr_speed_des[2]; /* # of wr speed perf descr. tables */ + struct cd_wr_speed_performance + wr_speed_des[1]; /* wr speed performance descriptor */ + /* Actually more (num_wr_speed_des) */ +}; + +#else /* Motorola byteorder */ + +struct cd_wr_speed_performance { + Uchar res0; /* Reserved */ + Ucbit res_1_27 : 6; /* Reserved */ + Ucbit rot_ctl_sel : 2; /* Rotational control selected */ + Uchar wr_speed_supp[2]; /* Supported write speed */ +}; + +struct cd_mode_page_2A { /* CD Cap / mech status */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x14 = 20 Bytes (MMC) */ + /* 0x18 = 24 Bytes (MMC-2) */ + /* 0x1C >= 28 Bytes (MMC-3) */ + Ucbit res_2_67 : 2; /* Reserved */ + Ucbit dvd_ram_read : 1; /* Reads DVD-RAM media */ + Ucbit dvd_r_read : 1; /* Reads DVD-R media */ + Ucbit dvd_rom_read : 1; /* Reads DVD ROM media */ + Ucbit method2 : 1; /* Reads fixed packet method2 media */ + Ucbit cd_rw_read : 1; /* Reads CD-RW media */ + Ucbit cd_r_read : 1; /* Reads CD-R media */ + Ucbit res_3_67 : 2; /* Reserved */ + Ucbit dvd_ram_write : 1; /* Supports writing DVD-RAM media */ + Ucbit dvd_r_write : 1; /* Supports writing DVD-R media */ + Ucbit res_3_3 : 1; /* Reserved */ + Ucbit test_write : 1; /* Supports emulation write */ + Ucbit cd_rw_write : 1; /* Supports writing CD-RW media */ + Ucbit cd_r_write : 1; /* Supports writing CD-R media */ + Ucbit BUF : 1; /* Supports Buffer under. free rec. */ + Ucbit multi_session : 1; /* Reads multi-session media */ + Ucbit mode_2_form_2 : 1; /* Reads Mode-2 form 2 media */ + Ucbit mode_2_form_1 : 1; /* Reads Mode-2 form 1 media (XA) */ + Ucbit digital_port_1 : 1; /* Supports digital output on port 1 */ + Ucbit digital_port_2 : 1; /* Supports digital output on port 2 */ + Ucbit composite : 1; /* Deliveres composite A/V stream */ + Ucbit audio_play : 1; /* Supports Audio play operation */ + Ucbit read_bar_code : 1; /* Supports reading bar codes */ + Ucbit UPC : 1; /* Reads media catalog number (UPC) */ + Ucbit ISRC : 1; /* Reads ISRC information */ + Ucbit c2_pointers : 1; /* Supports C2 error pointers */ + Ucbit rw_deint_corr : 1; /* Reads de-interleved R-W sub chan */ + Ucbit rw_supported : 1; /* Reads R-W sub channel information */ + Ucbit cd_da_accurate : 1; /* READ CD data stream is accurate */ + Ucbit cd_da_supported : 1; /* Reads audio data with READ CD cmd */ + Ucbit loading_type : 3; /* Loading mechanism type */ + Ucbit res_6_4 : 1; /* Reserved */ + Ucbit eject : 1; /* Ejects disc/cartr with STOP LoEj */ + Ucbit prevent_jumper : 1; /* State of prev/allow jumper 0=pres */ + Ucbit lock_state : 1; /* Lock state 0=unlocked 1=locked */ + Ucbit lock : 1; /* PREVENT/ALLOW may lock media */ + Ucbit res_7 : 2; /* Reserved */ + Ucbit pw_in_lead_in : 1; /* Reads raw P-W sucode from lead in */ + Ucbit side_change : 1; /* Side change capable */ + Ucbit sw_slot_sel : 1; /* Load empty slot in changer */ + Ucbit disk_present_rep: 1; /* Changer supports disk present rep */ + Ucbit sep_chan_mute : 1; /* Mute controls each channel separat*/ + Ucbit sep_chan_vol : 1; /* Vol controls each channel separat */ + Uchar max_read_speed[2]; /* Max. read speed in KB/s */ + Uchar num_vol_levels[2]; /* # of supported volume levels */ + Uchar buffer_size[2]; /* Buffer size for the data in KB */ + Uchar cur_read_speed[2]; /* Current read speed in KB/s */ + Uchar res_16; /* Reserved */ + Ucbit res_17 : 2; /* Reserved */ + Ucbit length : 2; /* 0=32BCKs 1=16BCKs 2=24BCKs 3=24I2c*/ + Ucbit LSBF : 1; /* Set: LSB first Clear: MSB first */ + Ucbit RCK : 1; /* Set: HIGH high LRCK=left channel */ + Ucbit BCK : 1; /* Data valid on falling edge of BCK */ + Ucbit res_17_0 : 1; /* Reserved */ + Uchar max_write_speed[2]; /* Max. write speed supported in KB/s*/ + Uchar cur_write_speed[2]; /* Current write speed in KB/s */ + + /* Byte 22 ... Only in MMC-2 */ + Uchar copy_man_rev[2]; /* Copy management revision supported*/ + Uchar res_24; /* Reserved */ + Uchar res_25; /* Reserved */ + + /* Byte 26 ... Only in MMC-3 */ + Uchar res_26; /* Reserved */ + Ucbit res_27_27 : 6; /* Reserved */ + Ucbit rot_ctl_sel : 2; /* Rotational control selected */ + Uchar v3_cur_write_speed[2]; /* Current write speed in KB/s */ + Uchar num_wr_speed_des[2]; /* # of wr speed perf descr. tables */ + struct cd_wr_speed_performance + wr_speed_des[1]; /* wr speed performance descriptor */ + /* Actually more (num_wr_speed_des) */ +}; + +#endif + +#define LT_CADDY 0 +#define LT_TRAY 1 +#define LT_POP_UP 2 +#define LT_RES3 3 +#define LT_CHANGER_IND 4 +#define LT_CHANGER_CART 5 +#define LT_RES6 6 +#define LT_RES7 7 + + +struct scsi_mode_data { + struct scsi_mode_header header; + struct scsi_mode_blockdesc blockdesc; + union pagex { + struct acb_mode_data acb; + struct scsi_mode_page_01 page1; + struct scsi_mode_page_02 page2; + struct scsi_mode_page_03 page3; + struct scsi_mode_page_04 page4; + struct scsi_mode_page_05 page5; + struct scsi_mode_page_07 page7; + struct scsi_mode_page_08 page8; + struct scsi_mode_page_09 page9; + struct scsi_mode_page_0A pageA; + struct scsi_mode_page_0B pageB; + struct scsi_mode_page_0C pageC; + struct scsi_mode_page_0D pageD; + struct sony_mode_page_20 sony20; + struct toshiba_mode_page_20 toshiba20; + struct ccs_mode_page_38 ccs38; + } pagex; +}; + +struct scsi_capacity { + Int32_t c_baddr; /* must convert byteorder!! */ + Int32_t c_bsize; /* must convert byteorder!! */ +}; + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_def_header { + Ucbit : 8; + Ucbit format : 3; + Ucbit gdl : 1; + Ucbit mdl : 1; + Ucbit : 3; + Uchar length[2]; +}; + +#else /* Motorola byteorder */ + +struct scsi_def_header { + Ucbit : 8; + Ucbit : 3; + Ucbit mdl : 1; + Ucbit gdl : 1; + Ucbit format : 3; + Uchar length[2]; +}; +#endif + + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_format_header { + Ucbit res : 8; /* Adaptec 5500: 1 --> format track */ + Ucbit vu : 1; /* Vendor Unique */ + Ucbit immed : 1; /* Return Immediately from Format */ + Ucbit tryout : 1; /* Check if format parameters OK */ + Ucbit ipattern : 1; /* Init patter descriptor present */ + Ucbit serr : 1; /* Stop on error */ + Ucbit dcert : 1; /* Disable certification */ + Ucbit dmdl : 1; /* Disable manufacturer defect list */ + Ucbit enable : 1; /* Enable to use the next 3 bits */ + Uchar length[2]; /* Length of following list in bytes*/ +}; + +#else /* Motorola byteorder */ + +struct scsi_format_header { + Ucbit res : 8; /* Adaptec 5500: 1 --> format track */ + Ucbit enable : 1; /* Enable to use the next 3 bits */ + Ucbit dmdl : 1; /* Disable manufacturer defect list */ + Ucbit dcert : 1; /* Disable certification */ + Ucbit serr : 1; /* Stop on error */ + Ucbit ipattern : 1; /* Init patter descriptor present */ + Ucbit tryout : 1; /* Check if format parameters OK */ + Ucbit immed : 1; /* Return Immediately from Format */ + Ucbit vu : 1; /* Vendor Unique */ + Uchar length[2]; /* Length of following list in bytes*/ +}; +#endif + +struct scsi_def_bfi { + Uchar cyl[3]; + Uchar head; + Uchar bfi[4]; +}; + +struct scsi_def_phys { + Uchar cyl[3]; + Uchar head; + Uchar sec[4]; +}; + +struct scsi_def_list { + struct scsi_def_header hd; + union { + Uchar list_block[1][4]; + struct scsi_def_bfi list_bfi[1]; + struct scsi_def_phys list_phys[1]; + } def_list; +}; + +struct scsi_format_data { + struct scsi_format_header hd; + union { + Uchar list_block[1][4]; + struct scsi_def_bfi list_bfi[1]; + struct scsi_def_phys list_phys[1]; + } def_list; +}; + +#define def_block def_list.list_block +#define def_bfi def_list.list_bfi +#define def_phys def_list.list_phys + +#define SC_DEF_BLOCK 0 +#define SC_DEF_BFI 4 +#define SC_DEF_PHYS 5 +#define SC_DEF_VU 6 +#define SC_DEF_RES 7 + +struct scsi_format_cap_header { + Uchar res[3]; /* Reserved */ + Uchar len; /* Len (a multiple of 8) */ +}; + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_format_cap_desc { + Uchar nblock[4]; /* Number of blocks */ + Ucbit desc_type : 2; /* Descriptor type */ + Ucbit fmt_type : 6; /* Format Taype */ + Uchar blen[3]; /* Logical block length */ +}; + +#else /* Motorola byteorder */ + +struct scsi_format_cap_desc { + Uchar nblock[4]; /* Number of blocks */ + Ucbit fmt_type : 6; /* Format Taype */ + Ucbit desc_type : 2; /* Descriptor type */ + Uchar blen[3]; /* Logical block length */ +}; +#endif + +/* + * Defines for 'fmt_type'. + */ +#define FCAP_TYPE_DVDPLUS_FULL 0x26 /* DVD+RW Full Format */ + +/* + * Defines for 'desc_type'. + * In case of FCAP_DESC_RES, the descriptor is a formatted capacity descriptor + * and the 'blen' field is type dependent. + * For all other cases, this is the Current/Maximum Capacity descriptor and + * the value of 'fmt_type' is reserved and must be zero. + */ +#define FCAP_DESC_RES 0 /* Reserved */ +#define FCAP_DESC_UNFORM 1 /* Unformatted Media */ +#define FCAP_DESC_FORM 2 /* Formatted Media */ +#define FCAP_DESC_NOMEDIA 3 /* No Media */ + +struct scsi_cap_data { + struct scsi_format_cap_header hd; + struct scsi_format_cap_desc list[1]; +}; + + +struct scsi_send_diag_cmd { + Uchar cmd; + Uchar addr[4]; + Ucbit : 8; +}; + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_sector_header { + Uchar cyl[2]; + Uchar head; + Uchar sec; + Ucbit : 5; + Ucbit rp : 1; + Ucbit sp : 1; + Ucbit dt : 1; +}; + +#else /* Motorola byteorder */ + +struct scsi_sector_header { + Uchar cyl[2]; + Uchar head; + Uchar sec; + Ucbit dt : 1; + Ucbit sp : 1; + Ucbit rp : 1; + Ucbit : 5; +}; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SCG_SCSIREG_H */ diff --git a/libusal/usal/scsisense.h b/libusal/usal/scsisense.h new file mode 100644 index 0000000..c5ee6ab --- /dev/null +++ b/libusal/usal/scsisense.h @@ -0,0 +1,216 @@ +/* + * 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. + * + */ + +/* @(#)scsisense.h 2.18 04/09/04 Copyright 1986 J. Schilling */ +/* + * Definitions for the SCSI status code and sense structure + * + * Copyright (c) 1986 J. Schilling + */ +/* + * 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. + */ + +#ifndef _SCG_SCSISENSE_H +#define _SCG_SCSISENSE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SCSI status completion block. + */ +#define SCSI_EXTENDED_STATUS + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_status { + Ucbit vu_00 : 1; /* vendor unique */ + Ucbit chk : 1; /* check condition: sense data available */ + Ucbit cm : 1; /* condition met */ + Ucbit busy : 1; /* device busy or reserved */ + Ucbit is : 1; /* intermediate status sent */ + Ucbit vu_05 : 1; /* vendor unique */ +#define st_scsi2 vu_05 /* SCSI-2 modifier bit */ + Ucbit vu_06 : 1; /* vendor unique */ + Ucbit st_rsvd : 1; /* reserved */ + +#ifdef SCSI_EXTENDED_STATUS +#define ext_st1 st_rsvd /* extended status (next byte valid) */ + /* byte 1 */ + Ucbit ha_er : 1; /* host adapter detected error */ + Ucbit reserved: 6; /* reserved */ + Ucbit ext_st2 : 1; /* extended status (next byte valid) */ + /* byte 2 */ + Uchar byte2; /* third byte */ +#endif /* SCSI_EXTENDED_STATUS */ +}; + +#else /* Motorola byteorder */ + +struct scsi_status { + Ucbit st_rsvd : 1; /* reserved */ + Ucbit vu_06 : 1; /* vendor unique */ + Ucbit vu_05 : 1; /* vendor unique */ +#define st_scsi2 vu_05 /* SCSI-2 modifier bit */ + Ucbit is : 1; /* intermediate status sent */ + Ucbit busy : 1; /* device busy or reserved */ + Ucbit cm : 1; /* condition met */ + Ucbit chk : 1; /* check condition: sense data available */ + Ucbit vu_00 : 1; /* vendor unique */ +#ifdef SCSI_EXTENDED_STATUS +#define ext_st1 st_rsvd /* extended status (next byte valid) */ + /* byte 1 */ + Ucbit ext_st2 : 1; /* extended status (next byte valid) */ + Ucbit reserved: 6; /* reserved */ + Ucbit ha_er : 1; /* host adapter detected error */ + /* byte 2 */ + Uchar byte2; /* third byte */ +#endif /* SCSI_EXTENDED_STATUS */ +}; +#endif + +/* + * OLD Standard (Non Extended) SCSI Sense. Used mainly by the + * Adaptec ACB 4000 which is the only controller that + * does not support the Extended sense format. + */ +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_sense { /* scsi sense for error classes 0-6 */ + Ucbit code : 7; /* error class/code */ + Ucbit adr_val : 1; /* sense data is valid */ +#ifdef comment + Ucbit high_addr:5; /* high byte of block addr */ + Ucbit rsvd : 3; +#else + Uchar high_addr; /* high byte of block addr */ +#endif + Uchar mid_addr; /* middle byte of block addr */ + Uchar low_addr; /* low byte of block addr */ +}; + +#else /* Motorola byteorder */ + +struct scsi_sense { /* scsi sense for error classes 0-6 */ + Ucbit adr_val : 1; /* sense data is valid */ + Ucbit code : 7; /* error class/code */ +#ifdef comment + Ucbit rsvd : 3; + Ucbit high_addr:5; /* high byte of block addr */ +#else + Uchar high_addr; /* high byte of block addr */ +#endif + Uchar mid_addr; /* middle byte of block addr */ + Uchar low_addr; /* low byte of block addr */ +}; +#endif + +/* + * SCSI extended sense parameter block. + */ +#ifdef comment +#define SC_CLASS_EXTENDED_SENSE 0x7 /* indicates extended sense */ +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct scsi_ext_sense { /* scsi extended sense for error class 7 */ + /* byte 0 */ + Ucbit type : 7; /* fixed at 0x70 */ + Ucbit adr_val : 1; /* sense data is valid */ + /* byte 1 */ + Uchar seg_num; /* segment number, applies to copy cmd only */ + /* byte 2 */ + Ucbit key : 4; /* sense key, see below */ + Ucbit : 1; /* reserved */ + Ucbit ili : 1; /* incorrect length indicator */ + Ucbit eom : 1; /* end of media */ + Ucbit fil_mk : 1; /* file mark on device */ + /* bytes 3 through 7 */ + Uchar info_1; /* information byte 1 */ + Uchar info_2; /* information byte 2 */ + Uchar info_3; /* information byte 3 */ + Uchar info_4; /* information byte 4 */ + Uchar add_len; /* number of additional bytes */ + /* bytes 8 through 13, CCS additions */ + Uchar optional_8; /* CCS search and copy only */ + Uchar optional_9; /* CCS search and copy only */ + Uchar optional_10; /* CCS search and copy only */ + Uchar optional_11; /* CCS search and copy only */ + Uchar sense_code; /* sense code */ + Uchar qual_code; /* sense code qualifier */ + Uchar fru_code; /* Field replacable unit code */ + Ucbit bptr : 3; /* bit pointer for failure (if bpv) */ + Ucbit bpv : 1; /* bit pointer is valid */ + Ucbit : 2; + Ucbit cd : 1; /* pointers refer to command not data */ + Ucbit sksv : 1; /* sense key specific valid */ + Uchar field_ptr[2]; /* field pointer for failure */ + Uchar add_info[2]; /* round up to 20 bytes */ +}; + +#else /* Motorola byteorder */ + +struct scsi_ext_sense { /* scsi extended sense for error class 7 */ + /* byte 0 */ + Ucbit adr_val : 1; /* sense data is valid */ + Ucbit type : 7; /* fixed at 0x70 */ + /* byte 1 */ + Uchar seg_num; /* segment number, applies to copy cmd only */ + /* byte 2 */ + Ucbit fil_mk : 1; /* file mark on device */ + Ucbit eom : 1; /* end of media */ + Ucbit ili : 1; /* incorrect length indicator */ + Ucbit : 1; /* reserved */ + Ucbit key : 4; /* sense key, see below */ + /* bytes 3 through 7 */ + Uchar info_1; /* information byte 1 */ + Uchar info_2; /* information byte 2 */ + Uchar info_3; /* information byte 3 */ + Uchar info_4; /* information byte 4 */ + Uchar add_len; /* number of additional bytes */ + /* bytes 8 through 13, CCS additions */ + Uchar optional_8; /* CCS search and copy only */ + Uchar optional_9; /* CCS search and copy only */ + Uchar optional_10; /* CCS search and copy only */ + Uchar optional_11; /* CCS search and copy only */ + Uchar sense_code; /* sense code */ + Uchar qual_code; /* sense code qualifier */ + Uchar fru_code; /* Field replacable unit code */ + Ucbit sksv : 1; /* sense key specific valid */ + Ucbit cd : 1; /* pointers refer to command not data */ + Ucbit : 2; + Ucbit bpv : 1; /* bit pointer is valid */ + Ucbit bptr : 3; /* bit pointer for failure (if bpv) */ + Uchar field_ptr[2]; /* field pointer for failure */ + Uchar add_info[2]; /* round up to 20 bytes */ +}; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SCG_SCSISENSE_H */ diff --git a/libusal/usal/scsitransp.h b/libusal/usal/scsitransp.h new file mode 100644 index 0000000..a4f2327 --- /dev/null +++ b/libusal/usal/scsitransp.h @@ -0,0 +1,264 @@ +/* + * 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. + * + */ + +/* @(#)scsitransp.h 1.54 03/05/03 Copyright 1995 J. Schilling */ +/* + * Definitions for commands that use functions from scsitransp.c + * + * Copyright (c) 1995 J. Schilling + */ +/* + * 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. + */ + +#ifndef _SCG_SCSITRANSP_H +#define _SCG_SCSITRANSP_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct usal_scsi SCSI; + +typedef struct { + int scsibus; /* SCSI bus # for next I/O */ + int target; /* SCSI target # for next I/O */ + int lun; /* SCSI lun # for next I/O */ +} usal_addr_t; + +#ifndef _SCG_SCGOPS_H +#include <usal/usalops.h> +#endif + +typedef int (*usal_cb_t)(void *); + +struct usal_scsi { + usal_ops_t *ops; /* Ptr to low level SCSI transport ops */ + int fd; /* File descriptor for next I/O */ + usal_addr_t addr; /* SCSI address for next I/O */ + int flags; /* Libusal flags (see below) */ + int dflags; /* Drive specific flags (see below) */ + int kdebug; /* Kernel debug value for next I/O */ + int debug; /* Debug value for SCSI library */ + int silent; /* Be silent if value > 0 */ + int verbose; /* Be verbose if value > 0 */ + int overbose; /* Be verbose in open() if value > 0 */ + int disre_disable; + int deftimeout; + int noparity; /* Do not use SCSI parity fo next I/O */ + int dev; /* from scsi_cdr.c */ + struct usal_cmd *scmd; + char *cmdname; + char *curcmdname; + BOOL running; + int error; /* libusal error number */ + + long maxdma; /* Max DMA limit for this open instance */ + long maxbuf; /* Cur DMA buffer limit for this inst. */ + /* This is the size behind bufptr */ + struct timeval *cmdstart; + struct timeval *cmdstop; + const char **nonstderrs; + void *local; /* Local data from the low level code */ + void *bufbase; /* needed for scsi_freebuf() */ + void *bufptr; /* DMA buffer pointer for appl. use */ + char *errstr; /* Error string for scsi_open/sendmcd */ + char *errbeg; /* Pointer to begin of not flushed data */ + char *errptr; /* Actual write pointer into errstr */ + void *errfile; /* FILE to write errors to. NULL for not*/ + /* writing and leaving errs in errstr */ + usal_cb_t cb_fun; + void *cb_arg; + + struct scsi_inquiry *inq; + struct scsi_capacity *cap; +}; + +/* + * Macros for accessing members of the usal address structure. + * usal_settarget() is the only function that is allowed to modify + * the values of the SCSI address. + */ +#define usal_scsibus(usalp) (usalp)->addr.scsibus +#define usal_target(usalp) (usalp)->addr.target +#define usal_lun(usalp) (usalp)->addr.lun + +/* + * Flags for struct SCSI: + */ +/* NONE yet */ + +/* + * Drive specific flags for struct SCSI: + */ +#define DRF_MODE_DMA_OVR 0x0001 /* Drive gives DMA overrun */ + /* on mode sense */ + +#define SCSI_ERRSTR_SIZE 4096 + +/* + * Libusal error codes: + */ +#define SCG_ERRBASE 1000000 +#define SCG_NOMEM 1000001 + +/* + * Function codes for usal_version(): + */ +#define SCG_VERSION 0 /* libusal or transport version */ +#define SCG_AUTHOR 1 /* Author of above */ +#define SCG_SCCS_ID 2 /* SCCS id of above */ +#define SCG_RVERSION 10 /* Remote transport version */ +#define SCG_RAUTHOR 11 /* Remote transport author */ +#define SCG_RSCCS_ID 12 /* Remote transport SCCS ID */ +#define SCG_KVERSION 20 /* Kernel transport version */ + +/* + * Function codes for usal_reset(): + */ +#define SCG_RESET_NOP 0 /* Test if reset is supported */ +#define SCG_RESET_TGT 1 /* Reset Target only */ +#define SCG_RESET_BUS 2 /* Reset complete SCSI Bus */ + +/* + * Helpers for the error buffer in SCSI* + */ +#define usal_errsize(usalp) ((usalp)->errptr - (usalp)->errstr) +#define usal_errrsize(usalp) (SCSI_ERRSTR_SIZE - usal_errsize(usalp)) + +/* + * From scsitransp.c: + */ +extern char *usal_version(SCSI *usalp, int what); +extern int usal__open(SCSI *usalp, char *device); +extern int usal__close(SCSI *usalp); +extern BOOL usal_havebus(SCSI *usalp, int); +extern int usal_initiator_id(SCSI *usalp); +extern int usal_isatapi(SCSI *usalp); +extern int usal_reset(SCSI *usalp, int what); +extern void *usal_getbuf(SCSI *usalp, long); +extern void usal_freebuf(SCSI *usalp); +extern long usal_bufsize(SCSI *usalp, long); +extern void usal_setnonstderrs(SCSI *usalp, const char **); +extern BOOL usal_yes(char *); +extern int usal_cmd(SCSI *usalp); +extern void usal_vhead(SCSI *usalp); +extern int usal_svhead(SCSI *usalp, char *buf, int maxcnt); +extern int usal_vtail(SCSI *usalp); +extern int usal_svtail(SCSI *usalp, int *retp, char *buf, int maxcnt); +extern void usal_vsetup(SCSI *usalp); +extern int usal_getresid(SCSI *usalp); +extern int usal_getdmacnt(SCSI *usalp); +extern BOOL usal_cmd_err(SCSI *usalp); +extern void usal_printerr(SCSI *usalp); +#ifdef EOF /* stdio.h has been included */ +extern void usal_fprinterr(SCSI *usalp, FILE *f); +#endif +extern int usal_sprinterr(SCSI *usalp, char *buf, int maxcnt); +extern int usal__sprinterr(SCSI *usalp, char *buf, int maxcnt); +extern void usal_printcdb(SCSI *usalp); +extern int usal_sprintcdb(SCSI *usalp, char *buf, int maxcnt); +extern void usal_printwdata(SCSI *usalp); +extern int usal_sprintwdata(SCSI *usalp, char *buf, int maxcnt); +extern void usal_printrdata(SCSI *usalp); +extern int usal_sprintrdata(SCSI *usalp, char *buf, int maxcnt); +extern void usal_printresult(SCSI *usalp); +extern int usal_sprintresult(SCSI *usalp, char *buf, int maxcnt); +extern void usal_printstatus(SCSI *usalp); +extern int usal_sprintstatus(SCSI *usalp, char *buf, int maxcnt); +#ifdef EOF /* stdio.h has been included */ +extern void usal_fprbytes(FILE *, char *, unsigned char *, int); +extern void usal_fprascii(FILE *, char *, unsigned char *, int); +#endif +extern void usal_prbytes(char *, unsigned char *, int); +extern void usal_prascii(char *, unsigned char *, int); +extern int usal_sprbytes(char *buf, int maxcnt, char *, unsigned char *, int); +extern int usal_sprascii(char *buf, int maxcnt, char *, unsigned char *, int); +#ifdef EOF /* stdio.h has been included */ +extern void usal_fprsense(FILE *f, unsigned char *, int); +#endif +extern void usal_prsense(unsigned char *, int); +extern int usal_sprsense(char *buf, int maxcnt, unsigned char *, int); +extern int usal_cmd_status(SCSI *usalp); +extern int usal_sense_key(SCSI *usalp); +extern int usal_sense_code(SCSI *usalp); +extern int usal_sense_qual(SCSI *usalp); +#ifdef _SCG_SCSIREG_H +#ifdef EOF /* stdio.h has been included */ +extern void usal_fprintdev(FILE *, struct scsi_inquiry *); +#endif +extern void usal_printdev(struct scsi_inquiry *); +#endif +extern int usal_printf(SCSI *usalp, const char *form, ...); +extern int usal_errflush(SCSI *usalp); +#ifdef EOF /* stdio.h has been included */ +extern int usal_errfflush(SCSI *usalp, FILE *f); +#endif + +/* + * From scsierrmsg.c: + */ +extern const char *usal_sensemsg(int, int, int, const char **, char *, + int maxcnt); +#ifdef _SCG_SCSISENSE_H +extern int usal__errmsg(SCSI *usalp, char *obuf, int maxcnt, + struct scsi_sense *, struct scsi_status *, int); +#endif + +/* + * From scsiopen.c: + */ +#ifdef EOF /* stdio.h has been included */ +extern int usal_help(FILE *f); +#endif +extern SCSI *usal_open(char *scsidev, char *errs, int slen, int odebug, + int be_verbose); +extern int usal_close(SCSI * usalp); +extern void usal_settimeout(SCSI * usalp, int timeout); +extern SCSI *usal_smalloc(void); +extern void usal_sfree(SCSI *usalp); + +/* + * From usalsettarget.c: + */ +extern int usal_settarget(SCSI *usalp, int scsibus, int target, int lun); + +/* + * From scsi-remote.c: + */ +extern usal_ops_t *usal_remote(void); + +/* + * From scsihelp.c: + */ +#ifdef EOF /* stdio.h has been included */ +extern void __usal_help(FILE *f, char *name, char *tcomment, char *tind, + char *tspec, char *texample, BOOL mayscan, + BOOL bydev); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SCG_SCSITRANSP_H */ diff --git a/libusal/usal/spti-wnt.h b/libusal/usal/spti-wnt.h new file mode 100644 index 0000000..3edbe8f --- /dev/null +++ b/libusal/usal/spti-wnt.h @@ -0,0 +1,143 @@ +/* + * 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. + * + */ + +/* + * distilled information from various header files from Microsoft's + * DDK for Windows NT 4.0 + */ +#ifndef _SCSIPT_H_INC +#define _SCSIPT_H_INC + +#include <windows.h> + +typedef struct { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + ULONG DataBufferOffset; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH; + + +typedef struct { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + PVOID DataBuffer; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; + + +typedef struct { + SCSI_PASS_THROUGH spt; + ULONG Filler; + UCHAR ucSenseBuf[32]; + UCHAR ucDataBuf[512]; +} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS; + + +typedef struct { + SCSI_PASS_THROUGH_DIRECT spt; + ULONG Filler; + UCHAR ucSenseBuf[32]; +} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; + + + +typedef struct { + UCHAR NumberOfLogicalUnits; + UCHAR InitiatorBusId; + ULONG InquiryDataOffset; +} SCSI_BUS_DATA, *PSCSI_BUS_DATA; + + +typedef struct { + UCHAR NumberOfBusses; + SCSI_BUS_DATA BusData[1]; +} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO; + + +typedef struct { + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + BOOLEAN DeviceClaimed; + ULONG InquiryDataLength; + ULONG NextInquiryDataOffset; + UCHAR InquiryData[1]; +} SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA; + + +typedef struct { + ULONG Length; + UCHAR PortNumber; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; +} SCSI_ADDRESS, *PSCSI_ADDRESS; + + +/* + * method codes + */ +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +/* + * file access values + */ +#define FILE_ANY_ACCESS 0 +#define FILE_READ_ACCESS 0x0001 +#define FILE_WRITE_ACCESS 0x0002 + + +#define IOCTL_SCSI_BASE 0x00000004 + +/* + * constants for DataIn member of SCSI_PASS_THROUGH* structures + */ +#define SCSI_IOCTL_DATA_OUT 0 +#define SCSI_IOCTL_DATA_IN 1 +#define SCSI_IOCTL_DATA_UNSPECIFIED 2 + +/* + * Standard IOCTL define + */ +#define CTL_CODE(DevType, Function, Method, Access) \ + (((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) + +#define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_SCSI_MINIPORT CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_SCSI_GET_ADDRESS CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#endif diff --git a/libusal/usal/srb_os2.h b/libusal/usal/srb_os2.h new file mode 100644 index 0000000..54f57ca --- /dev/null +++ b/libusal/usal/srb_os2.h @@ -0,0 +1,179 @@ +/* + * 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. + * + */ + +/* @(#)srb_os2.h 1.1 98/11/01 Copyright 1998 D. Dorau, C. Wohlgemuth J. Schilling */ +/* + * Definitions for ASPI-Router (ASPIROUT.SYS). + * + * Copyright (c) 1998 D. Dorau, C. Wohlgemuth + */ + +/* + * 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. + */ + +#pragma pack(1) + + /* SRB command */ +#define SRB_Inquiry 0x00 +#define SRB_Device 0x01 +#define SRB_Command 0x02 +#define SRB_Abort 0x03 +#define SRB_Reset 0x04 +#define SRB_Param 0x05 + + /* SRB status */ +#define SRB_Busy 0x00 /* SCSI request in progress */ +#define SRB_Done 0x01 /* SCSI request completed without error */ +#define SRB_Aborted 0x02 /* SCSI aborted by host */ +#define SRB_BadAbort 0x03 /* Unable to abort SCSI request */ +#define SRB_Error 0x04 /* SCSI request completed with error */ +#define SRB_BusyPost 0x10 /* SCSI request in progress with POST - Nokia */ +#define SRB_InvalidCmd 0x80 /* Invalid SCSI request */ +#define SRB_InvalidHA 0x81 /* Invalid Hhost adapter number */ +#define SRB_BadDevice 0x82 /* SCSI device not installed */ + + /* SRB flags */ +#define SRB_Post 0x01 /* Post vector valid */ +#define SRB_Link 0x02 /* Link vector valid */ +#define SRB_SG 0x04 /* Nokia: scatter/gather */ + /* S/G: n * (4 bytes length, 4 bytes addr) */ + /* No of s/g items not limited by HA spec. */ +#define SRB_NoCheck 0x00 /* determined by command, not checked */ +#define SRB_Read 0x08 /* target to host, length checked */ +#define SRB_Write 0x10 /* host to target, length checked */ +#define SRB_NoTransfer 0x18 /* no data transfer */ +#define SRB_DirMask 0x18 /* bit mask */ + + /* SRB host adapter status */ +#define SRB_NoError 0x00 /* No host adapter detected error */ +#define SRB_Timeout 0x11 /* Selection timeout */ +#define SRB_DataLength 0x12 /* Data over/underrun */ +#define SRB_BusFree 0x13 /* Unexpected bus free */ +#define SRB_BusSequence 0x14 /* Target bus sequence failure */ + + /* SRB target status field */ +#define SRB_NoStatus 0x00 /* No target status */ +#define SRB_CheckStatus 0x02 /* Check status (sense data valid) */ +#define SRB_LUN_Busy 0x08 /* Specified LUN is busy */ +#define SRB_Reserved 0x18 /* Reservation conflict */ + +#define MaxCDBStatus 64 /* max size of CDB + status */ + + +typedef struct SRb { + unsigned char cmd, /* 00 */ + status, /* 01 */ + ha_num, /* 02 */ + flags; /* 03 */ + unsigned long res_04_07; /* 04..07 */ + union { /* 08 */ + + /* SRB_Inquiry */ + struct { + unsigned char num_ha, /* 08 */ + ha_target, /* 09 */ + aspimgr_id[16], /* 0A..19 */ + host_id[16], /* 1A..29 */ + unique_id[16]; /* 2A..39 */ + } inq; + + /* SRB_Device */ + struct { + unsigned char target, /* 08 */ + lun, /* 09 */ + devtype; /* 0A */ + } dev; + + /* SRB_Command */ + struct { + unsigned char target, /* 08 */ + lun; /* 09 */ + unsigned long data_len; /* 0A..0D */ + unsigned char sense_len; /* 0E */ + unsigned long data_ptr; /* 0F..12 */ + unsigned long link_ptr; /* 13..16 */ + // void * _Seg16 data_ptr; /* 0F..12 */ + // void * _Seg16 link_ptr; /* 13..16 */ + unsigned char cdb_len, /* 17 */ + ha_status, /* 18 */ + target_status; /* 19 */ + unsigned char _Seg16postSRB[4]; + // void (* _Seg16 post) (SRB *); /* 1A..1D */ + unsigned char res_1E_29[12]; /* 1E..29 */ + unsigned char res_2A_3F[22]; /* 2A..3F */ + unsigned char cdb_st[64]; /* 40..7F CDB+status */ + unsigned char res_80_BF[64]; /* 80..BF */ + } cmd; + + /* SRB_Abort */ + struct { + unsigned char _Seg16srb[4]; + // void * _Seg16 srb; /* 08..0B */ + } abt; + + /* SRB_Reset */ + struct { + unsigned char target, /* 08 */ + lun, /* 09 */ + res_0A_17[14], /* 0A..17 */ + ha_status, /* 18 */ + target_status; /* 19 */ + } res; + + /* SRB_Param - unused by ASPI4OS2 */ + struct { + unsigned char unique[16]; /* 08..17 */ + } par; + + } u; +} SRB; + + +// SCSI sense codes +// Note! This list may not be complete. I did this compilation for use with tape drives. + +#define Sense_Current 0x70; // Current Error +#define Sense_Deferred 0x71; // Deferred Error +#define Sense_Filemark 0x80; // Filemark detected +#define Sense_EOM 0x40; // End of medium detected +#define Sense_ILI 0x20; // Incorrect length indicator + +// Sense Keys + +#define SK_NoSense 0x00; // No Sense +#define SK_RcvrdErr 0x01; // Recovered Error +#define SK_NotReady 0x02; // Not ready +#define SK_MedErr 0x03; // Medium Error +#define SK_HWErr 0x04; // Hardware Error +#define SK_IllReq 0x05; // Illegal Request +#define SK_UnitAtt 0x06; // Unit attention +#define SK_DataProt 0x07: // Data Protect +#define SK_BlankChk 0x08: // Blank Check +#define SK_VndSpec 0x09; // Vendor Specific +#define SK_CopyAbort 0x0A; // Copy Aborted +#define SK_AbtdCmd 0x0B; // Aborted Command +#define SK_Equal 0x0C; // Equal +#define SK_VolOvfl 0x0D; // Volume Overflow +#define SK_MisComp 0x0E; // Miscompare +#define SK_Reserved 0x0F; // Reserved diff --git a/libusal/usal/usalcmd.h b/libusal/usal/usalcmd.h new file mode 100644 index 0000000..47893ee --- /dev/null +++ b/libusal/usal/usalcmd.h @@ -0,0 +1,211 @@ +/* + * 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. + * + */ + +/* @(#)usalcmd.h 2.22 04/09/04 Copyright 1986 J. Schilling */ +/* + * Definitions for the SCSI 'usal_cmd' structure that has been created + * for the SCSI general driver 'usal' for SunOS and Solaris but + * now is used for wrapping general libusal SCSI transport requests. + * + * Copyright (c) 1986 J. Schilling + */ +/* + * 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. + */ + +#ifndef _SCG_SCGCMD_H +#define _SCG_SCGCMD_H + +#include <utypes.h> +#include <btorder.h> + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ +#else +# if defined(_BIT_FIELDS_HTOL) /* Motorola byteorder */ +# else +/* + * #error will not work for all compilers (e.g. sunos4) + * The following line will abort compilation on all compilers + * if none of the above is defines. And that's what we want. + */ +error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +# endif +#endif + +#include <usal/scsisense.h> +#include <usal/scsicdb.h> +#include <intcvt.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Leave these definitions here if possible to avoid the need to + * include scsireg.h which makes problems on some OS because these + * OS define the same types as in scsireg.h + */ + +/* + * SCSI status bits. + */ +#define ST_VU_00 0x01 /* Vendor unique */ +#define ST_CHK_COND 0x02 /* Check condition */ +#define ST_COND_MET 0x04 /* Condition met */ +#define ST_BUSY 0x08 /* Busy */ +#define ST_IS_SEND 0x10 /* Intermediate status send */ +#define ST_VU_05 0x20 /* Vendor unique */ +#define ST_VU_06 0x40 /* Vendor unique */ +#define ST_RSVD_07 0x80 /* Reserved */ + +/* + * Sense key values for extended sense. + */ +#define SC_NO_SENSE 0x00 +#define SC_RECOVERABLE_ERROR 0x01 +#define SC_NOT_READY 0x02 +#define SC_MEDIUM_ERROR 0x03 +#define SC_HARDWARE_ERROR 0x04 +#define SC_ILLEGAL_REQUEST 0x05 +#define SC_UNIT_ATTENTION 0x06 +#define SC_WRITE_PROTECT 0x07 +#define SC_BLANK_CHECK 0x08 +#define SC_VENDOR_UNIQUE 0x09 +#define SC_COPY_ABORTED 0x0A +#define SC_ABORTED_COMMAND 0x0B +#define SC_EQUAL 0x0C +#define SC_VOLUME_OVERFLOW 0x0D +#define SC_MISCOMPARE 0x0E +#define SC_RESERVED 0x0F + +/* + * Messages that SCSI can send. + */ +#define SC_COMMAND_COMPLETE 0x00 +#define SC_SYNCHRONOUS 0x01 +#define SC_SAVE_DATA_PTR 0x02 +#define SC_RESTORE_PTRS 0x03 +#define SC_DISCONNECT 0x04 +#define SC_ABORT 0x06 +#define SC_MSG_REJECT 0x07 +#define SC_NO_OP 0x08 +#define SC_PARITY 0x09 +#define SC_IDENTIFY 0x80 +#define SC_DR_IDENTIFY 0xc0 +#define SC_DEVICE_RESET 0x0c + +#define SC_G0_CDBLEN 6 /* Len of Group 0 commands */ +#define SC_G1_CDBLEN 10 /* Len of Group 1 commands */ +#define SC_G5_CDBLEN 12 /* Len of Group 5 commands */ + +#define SCG_MAX_CMD 24 /* 24 bytes max. size is supported */ +#define SCG_MAX_STATUS 3 /* XXX (sollte 4 allign.) Mamimum Status Len */ +#define SCG_MAX_SENSE 32 /* Mamimum Sense Len for auto Req. Sense */ + +#define DEF_SENSE_LEN 16 /* Default Sense Len */ +#define CCS_SENSE_LEN 18 /* Sense Len for CCS compatible devices */ + +struct usal_cmd { + caddr_t addr; /* Address of data in user space */ + int size; /* DMA count for data transfer */ + int flags; /* see below for definition */ + int cdb_len; /* Size of SCSI command in bytes */ + /* NOTE: rel 4 uses this field only */ + /* with commands not in group 1 or 2*/ + int sense_len; /* for intr() if -1 don't get sense */ + int timeout; /* timeout in seconds */ + /* NOTE: actual resolution depends */ + /* on driver implementation */ + int kdebug; /* driver kernel debug level */ + int resid; /* Bytes not transfered */ + int error; /* Error code from usalintr() */ + int ux_errno; /* UNIX error code */ +#ifdef comment +XXX struct scsi_status scb; ??? /* Status returnd by command */ +#endif + union { + struct scsi_status Scb; /* Status returnd by command */ + Uchar cmd_scb[SCG_MAX_STATUS]; + } u_scb; +#define scb u_scb.Scb +#ifdef comment +XXX struct scsi_sense sense; ??? /* Sense bytes from command */ +#endif + union { + struct scsi_sense Sense; /* Sense bytes from command */ + Uchar cmd_sense[SCG_MAX_SENSE]; + } u_sense; +#define sense u_sense.Sense + int sense_count; /* Number of bytes valid in sense */ + int target; /* SCSI target id */ + /* NOTE: The SCSI target id field */ + /* does not need to be filled unless */ + /* the low level transport is a real */ + /* usal driver. In this case the low */ + /* level transport routine of libusal */ + /* will fill in the needed value */ + union { /* SCSI command descriptor block */ + struct scsi_g0cdb g0_cdb; + struct scsi_g1cdb g1_cdb; + struct scsi_g5cdb g5_cdb; + Uchar cmd_cdb[SCG_MAX_CMD]; + } cdb; /* 24 bytes max. size is supported */ +}; + +#define dma_read flags /* 1 if DMA to Sun, 0 otherwise */ + +/* + * definition for flags field in usal_cmd struct + */ +#define SCG_RECV_DATA 0x0001 /* DMA direction to Sun */ +#define SCG_DISRE_ENA 0x0002 /* enable disconnect/reconnect */ +#define SCG_SILENT 0x0004 /* be silent on errors */ +#define SCG_CMD_RETRY 0x0008 /* enable retries */ +#define SCG_NOPARITY 0x0010 /* disable parity for this command */ + +/* + * definition for error field in usal_cmd struct + * + * The codes refer to SCSI general errors, not to device + * specific errors. Device specific errors are discovered + * by checking the sense data. + * The distinction between retryable and fatal is somewhat ad hoc. + */ +#define SCG_NO_ERROR 0 /* cdb transported without error */ + /* SCG_NO_ERROR incudes all commands */ + /* where the SCSI status is valid */ + +#define SCG_RETRYABLE 1 /* any other case e.g. SCSI bus busy */ + /* SCSI cdb could not be send, */ + /* includes DMA errors other than */ + /* DMA underrun */ + +#define SCG_FATAL 2 /* could not select target */ +#define SCG_TIMEOUT 3 /* driver timed out */ + + +#ifdef __cplusplus +} +#endif + +#endif /* _SCG_SCGCMD_H */ diff --git a/libusal/usal/usalio.h b/libusal/usal/usalio.h new file mode 100644 index 0000000..7624775 --- /dev/null +++ b/libusal/usal/usalio.h @@ -0,0 +1,79 @@ +/* + * 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. + * + */ + +/* @(#)usalio.h 2.16 00/11/07 Copyright 1986 J. Schilling */ +/* + * Definitions for the SCSI general driver 'usal' + * + * Copyright (c) 1986 J. Schilling + */ +/* + * 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. + */ + +#ifndef _SCG_SCGIO_H +#define _SCG_SCGIO_H + +#ifndef _SCG_SCGCMD_H +#include <usal/usalcmd.h> +#endif + +#if defined(SVR4) +#include <sys/ioccom.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__STDC__) || defined(SVR4) +#define SCGIOCMD _IOWR('G', 1, struct usal_cmd) /* do a SCSI cmd */ +#define SCGIORESET _IO('G', 2) /* reset SCSI bus */ +#define SCGIOGDISRE _IOR('G', 4, int) /* get sc disre Val*/ +#define SCGIOSDISRE _IOW('G', 5, int) /* set sc disre Val*/ +#define SCGIOIDBG _IO('G', 100) /* Inc Debug Val */ +#define SCGIODDBG _IO('G', 101) /* Dec Debug Val */ +#define SCGIOGDBG _IOR('G', 102, int) /* get Debug Val */ +#define SCGIOSDBG _IOW('G', 103, int) /* set Debug Val */ +#define SCIOGDBG _IOR('G', 104, int) /* get sc Debug Val*/ +#define SCIOSDBG _IOW('G', 105, int) /* set sc Debug Val*/ +#else +#define SCGIOCMD _IOWR(G, 1, struct usal_cmd) /* do a SCSI cmd */ +#define SCGIORESET _IO(G, 2) /* reset SCSI bus */ +#define SCGIOGDISRE _IOR(G, 4, int) /* get sc disre Val*/ +#define SCGIOSDISRE _IOW(G, 5, int) /* set sc disre Val*/ +#define SCGIOIDBG _IO(G, 100) /* Inc Debug Val */ +#define SCGIODDBG _IO(G, 101) /* Dec Debug Val */ +#define SCGIOGDBG _IOR(G, 102, int) /* get Debug Val */ +#define SCGIOSDBG _IOW(G, 103, int) /* set Debug Val */ +#define SCIOGDBG _IOR(G, 104, int) /* get sc Debug Val*/ +#define SCIOSDBG _IOW(G, 105, int) /* set sc Debug Val*/ +#endif + +#define SCGIO_CMD SCGIOCMD /* backward ccompatibility */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SCG_SCGIO_H */ diff --git a/libusal/usal/usalops.h b/libusal/usal/usalops.h new file mode 100644 index 0000000..5e367a6 --- /dev/null +++ b/libusal/usal/usalops.h @@ -0,0 +1,85 @@ +/* + * 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. + * + */ + +/* @(#)usalops.h 1.5 02/10/19 Copyright 2000 J. Schilling */ +/* + * Copyright (c) 2000 J. Schilling + */ +/* + * 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. + */ + +#ifndef _SCG_SCGOPS_H +#define _SCG_SCGOPS_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct usal_ops { + int (*usalo_send)(SCSI *usalp); + + char * (*usalo_version)(SCSI *usalp, int what); +#ifdef EOF /* stdio.h has been included */ + int (*usalo_help)(SCSI *usalp, FILE *f); +#else + int (*usalo_help)(SCSI *usalp, void *f); +#endif + int (*usalo_open)(SCSI *usalp, char *device); + int (*usalo_close)(SCSI *usalp); + long (*usalo_maxdma)(SCSI *usalp, long amt); + void * (*usalo_getbuf)(SCSI *usalp, long amt); + void (*usalo_freebuf)(SCSI *usalp); + + + BOOL (*usalo_havebus)(SCSI *usalp, int busno); + int (*usalo_fileno)(SCSI *usalp, int busno, int tgt, int tlun); + + int (*usalo_initiator_id)(SCSI *usalp); + int (*usalo_isatapi)(SCSI *usalp); + int (*usalo_reset)(SCSI *usalp, int what); + + char * (*usalo_natname)(SCSI *usalp, int busno, int tgt, int tlun); +} usal_ops_t; + +#define SCGO_SEND(usalp) (*(usalp)->ops->usalo_send)(usalp) +#define SCGO_VERSION(usalp, what) (*(usalp)->ops->usalo_version)(usalp, what) +#define SCGO_HELP(usalp, f) (*(usalp)->ops->usalo_help)(usalp, f) +#define SCGO_OPEN(usalp, device) (*(usalp)->ops->usalo_open)(usalp, device) +#define SCGO_CLOSE(usalp) (*(usalp)->ops->usalo_close)(usalp) +#define SCGO_MAXDMA(usalp, amt) (*(usalp)->ops->usalo_maxdma)(usalp, amt) +#define SCGO_GETBUF(usalp, amt) (*(usalp)->ops->usalo_getbuf)(usalp, amt) +#define SCGO_FREEBUF(usalp) (*(usalp)->ops->usalo_freebuf)(usalp) +#define SCGO_HAVEBUS(usalp, busno) (*(usalp)->ops->usalo_havebus)(usalp, busno) +#define SCGO_FILENO(usalp, busno, tgt, tlun) (*(usalp)->ops->usalo_fileno)(usalp, busno, tgt, tlun) +#define SCGO_INITIATOR_ID(usalp) (*(usalp)->ops->usalo_initiator_id)(usalp) +#define SCGO_ISATAPI(usalp) (*(usalp)->ops->usalo_isatapi)(usalp) +#define SCGO_RESET(usalp, what) (*(usalp)->ops->usalo_reset)(usalp, what) + +extern int usal_fileno(SCSI *usalp, int busno, int tgt, int tlun); +extern char * usal_natname(SCSI *usalp, int busno, int tgt, int tlun); +#ifdef __cplusplus +} +#endif + +#endif /* _SCG_SCGOPS_H */ diff --git a/libusal/usalsettarget.c b/libusal/usalsettarget.c new file mode 100644 index 0000000..009805c --- /dev/null +++ b/libusal/usalsettarget.c @@ -0,0 +1,58 @@ +/* + * 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. + * + */ + +/* @(#)usalsettarget.c 1.2 04/01/14 Copyright 2000 J. Schilling */ +/* + * usal Library + * set target SCSI address + * + * This is the only place in libusal that is allowed to assign + * values to the usal address structure. + * + * Copyright (c) 2000 J. Schilling + */ +/* + * 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. + */ + +#include <mconfig.h> +#include <standard.h> +#include <schily.h> + +#include <usal/scsitransp.h> + +int usal_settarget(SCSI *usalp, int, int, int); + +int +usal_settarget(SCSI *usalp, int busno, int tgt, int tlun) +{ + int fd = -1; + + if (usalp->ops != NULL) + fd = SCGO_FILENO(usalp, busno, tgt, tlun); + usalp->fd = fd; + usal_scsibus(usalp) = busno; + usal_target(usalp) = tgt; + usal_lun(usalp) = tlun; + return (fd); +} diff --git a/libusal/usaltimes.c b/libusal/usaltimes.c new file mode 100644 index 0000000..d8e28d7 --- /dev/null +++ b/libusal/usaltimes.c @@ -0,0 +1,60 @@ +/* + * 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. + * + */ + +/* @(#)usaltimes.c 1.1 00/08/25 Copyright 1995,2000 J. Schilling */ +/* + * SCSI user level command timing + * + * Copyright (c) 1995,2000 J. Schilling + */ +/* + * 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. + */ + +#include <mconfig.h> +#include <standard.h> +#include <timedefs.h> +#include <schily.h> + +#include <usal/scsitransp.h> +#include "usaltimes.h" + +void __usal_times(SCSI *usalp); + +/* + * We don't like to make this a public interface to prevent bad users + * from making our timing incorrect. + */ +void +__usal_times(SCSI *usalp) +{ + struct timeval *stp = usalp->cmdstop; + + gettimeofday(stp, (struct timezone *)0); + stp->tv_sec -= usalp->cmdstart->tv_sec; + stp->tv_usec -= usalp->cmdstart->tv_usec; + while (stp->tv_usec < 0) { + stp->tv_sec -= 1; + stp->tv_usec += 1000000; + } +} diff --git a/libusal/usaltimes.h b/libusal/usaltimes.h new file mode 100644 index 0000000..cf0a207 --- /dev/null +++ b/libusal/usaltimes.h @@ -0,0 +1,34 @@ +/* + * 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. + * + */ + +/* @(#)usaltimes.h 1.1 00/08/25 Copyright 1995,2000 J. Schilling */ +/* + * SCSI user level command timing + * + * Copyright (c) 1995,2000 J. Schilling + */ +/* + * 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. + */ + +extern void __usal_times(SCSI *usalp); |