/* * 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 /* * 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