summaryrefslogtreecommitdiff
path: root/libusal
diff options
context:
space:
mode:
authorPhilippe Coval <philippe.coval@eurogiciel.fr>2013-03-01 11:33:00 +0100
committerPhilippe Coval <philippe.coval@eurogiciel.fr>2013-03-01 11:33:00 +0100
commita119991b98b043ef5a2432a7a0e2c4f2cf484674 (patch)
tree7346d42a282562a3937d82307012b5857d642ce6 /libusal
parent17a3b002800b60ee4863bd971c0068c324a27fd7 (diff)
downloadcdrkit-upstream.tar.gz
cdrkit-upstream.tar.bz2
cdrkit-upstream.zip
Imported Upstream version 1.1.11upstream/1.1.11upstream
Diffstat (limited to 'libusal')
-rw-r--r--libusal/CMakeLists.txt10
-rw-r--r--libusal/pg.h75
-rw-r--r--libusal/rdummy.c49
-rw-r--r--libusal/scsi-aix.c428
-rw-r--r--libusal/scsi-amigaos.c771
-rw-r--r--libusal/scsi-apollo.c550
-rw-r--r--libusal/scsi-beos.c414
-rw-r--r--libusal/scsi-bsd-os.c443
-rw-r--r--libusal/scsi-bsd.c992
-rw-r--r--libusal/scsi-dos.c562
-rw-r--r--libusal/scsi-hpux.c363
-rw-r--r--libusal/scsi-linux-ata.c1188
-rw-r--r--libusal/scsi-linux-pg.c587
-rw-r--r--libusal/scsi-linux-sg.c1754
-rw-r--r--libusal/scsi-mac-iokit.c539
-rw-r--r--libusal/scsi-next.c419
-rw-r--r--libusal/scsi-openserver.c1015
-rw-r--r--libusal/scsi-os2.c630
-rw-r--r--libusal/scsi-osf.c445
-rw-r--r--libusal/scsi-qnx.c316
-rw-r--r--libusal/scsi-remote.c1213
-rw-r--r--libusal/scsi-sgi.c479
-rw-r--r--libusal/scsi-sun.c1133
-rw-r--r--libusal/scsi-unixware.c922
-rw-r--r--libusal/scsi-vms.c540
-rw-r--r--libusal/scsi-wnt.c1848
-rw-r--r--libusal/scsierrs.c1008
-rw-r--r--libusal/scsihack.c483
-rw-r--r--libusal/scsihelp.c56
-rw-r--r--libusal/scsiopen.c464
-rw-r--r--libusal/scsitransp.c1345
-rw-r--r--libusal/usal/aspi-dos.h169
-rw-r--r--libusal/usal/aspi-win32.h208
-rw-r--r--libusal/usal/scsicdb.h260
-rw-r--r--libusal/usal/scsidefs.h136
-rw-r--r--libusal/usal/scsireg.h1240
-rw-r--r--libusal/usal/scsisense.h216
-rw-r--r--libusal/usal/scsitransp.h264
-rw-r--r--libusal/usal/spti-wnt.h143
-rw-r--r--libusal/usal/srb_os2.h179
-rw-r--r--libusal/usal/usalcmd.h211
-rw-r--r--libusal/usal/usalio.h79
-rw-r--r--libusal/usal/usalops.h85
-rw-r--r--libusal/usalsettarget.c58
-rw-r--r--libusal/usaltimes.c60
-rw-r--r--libusal/usaltimes.h34
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);