summaryrefslogtreecommitdiff
path: root/libusal/scsi-sun.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-12-31 05:04:42 +0400
committerIgor Pashev <pashev.igor@gmail.com>2012-12-31 05:04:42 +0400
commit71dc8760ff4de5f365330d1bc571d934deb54af9 (patch)
tree7346d42a282562a3937d82307012b5857d642ce6 /libusal/scsi-sun.c
downloadcdrkit-71dc8760ff4de5f365330d1bc571d934deb54af9.tar.gz
Imported Upstream version 1.1.11upstream/1.1.11upstream
Diffstat (limited to 'libusal/scsi-sun.c')
-rw-r--r--libusal/scsi-sun.c1133
1 files changed, 1133 insertions, 0 deletions
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 */