diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2012-12-31 05:04:42 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2012-12-31 05:04:42 +0400 |
commit | 71dc8760ff4de5f365330d1bc571d934deb54af9 (patch) | |
tree | 7346d42a282562a3937d82307012b5857d642ce6 /libusal/scsi-openserver.c | |
download | cdrkit-71dc8760ff4de5f365330d1bc571d934deb54af9.tar.gz |
Imported Upstream version 1.1.11upstream/1.1.11upstream
Diffstat (limited to 'libusal/scsi-openserver.c')
-rw-r--r-- | libusal/scsi-openserver.c | 1015 |
1 files changed, 1015 insertions, 0 deletions
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 |