Files
mtx/mtx-1.3.12/du/scsi.c
2018-07-31 15:07:09 -05:00

215 lines
5.5 KiB
C

/* SCSI.C - Digital Unix-specific SCSI routines.
**
** TECSys Development, Inc., April 1998
**
** This module began life as a part of XMCD, an X-windows CD player
** program for many platforms. No real functionality from the original XMCD
** is present in this module, but in the interest of making certain that
** proper credit is given where it may be due, the copyrights and inclusions
** from the XMCD module OS_DEC.C are included below.
**
** The portions of coding in this module ascribable to TECSys Development
** are hereby also released under the terms and conditions of version 2
** of the GNU General Public License as described below....
*/
/*
* libdi - scsipt SCSI Device Interface Library
*
* Copyright (C) 1993-1997 Ti Kan
* E-mail: ti@amb.org
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Digital UNIX (OSF/1) and Ultrix support
*
* Contributing author: Matt Thomas
* E-Mail: thomas@lkg.dec.com
*
* This software fragment contains code that interfaces the
* application to the Digital UNIX and Ultrix operating systems.
* The term Digital, Ultrix and OSF/1 are used here for identification
* purposes only.
*/
static int bus = -1,
target = -1,
lun = -1;
static int SCSI_OpenDevice(char *DeviceName)
{
int fd;
struct stat stbuf;
int saverr;
/* Check for validity of device node */
if (stat(DeviceName, &stbuf) < 0)
{
FatalError("cannot stat SCSI device '%s' - %m\n", DeviceName);
}
if (!S_ISCHR(stbuf.st_mode))
{
FatalError("device '%s': not appropriate device type - %m\n", DeviceName);
}
if ((fd = open(DeviceName, O_RDONLY | O_NDELAY, 0)) >= 0)
{
struct devget devget;
if (ioctl(fd, DEVIOCGET, &devget) >= 0)
{
#ifdef __osf__
lun = devget.slave_num % 8;
devget.slave_num /= 8;
#else
lun = 0;
#endif
target = devget.slave_num % 8;
devget.slave_num /= 8;
bus = devget.slave_num % 8;
(void) close(fd);
if ((fd = open(DEV_CAM, O_RDWR, 0)) >= 0 ||
(fd = open(DEV_CAM, O_RDONLY, 0)) >= 0)
{
return (fd);
}
fd = bus = target = lun = -1;
FatalError("error %d opening SCSI device '%s' - %m\n",
errno, DEV_CAM);
}
else
{
(void) close(fd);
fd = bus = target = lun = -1;
FatalError("error %d on DEVIOCGET ioctl for '%s' - %m\n",
errno, DeviceName);
}
}
else
{
saverr = errno;
fd = bus = target = lun = -1;
FatalError("cannot open SCSI device '%s', error %d - %m\n",
DeviceName, saverr);
}
fd = bus = target = lun = -1;
return -1;
}
static void SCSI_CloseDevice(char *DeviceName, int DeviceFD)
{
(void) close(DeviceFD);
bus = target = lun = -1;
}
static int SCSI_ExecuteCommand(int DeviceFD,
Direction_T Direction,
CDB_T *CDB,
int CDB_Length,
void *DataBuffer,
int DataBufferLength,
RequestSense_T *RequestSense)
{
UAGT_CAM_CCB uagt;
CCB_SCSIIO ccb;
if (DeviceFD < 0)
return -1;
(void) memset(&uagt, 0, sizeof(uagt));
(void) memset(&ccb, 0, sizeof(ccb));
/* Setup the user agent ccb */
uagt.uagt_ccb = (CCB_HEADER *) &ccb;
uagt.uagt_ccblen = sizeof(CCB_SCSIIO);
/* Setup the scsi ccb */
(void) memcpy((unsigned char *) ccb.cam_cdb_io.cam_cdb_bytes,
CDB, CDB_Length);
ccb.cam_cdb_len = CDB_Length;
ccb.cam_ch.my_addr = (CCB_HEADER *) &ccb;
ccb.cam_ch.cam_ccb_len = sizeof(CCB_SCSIIO);
ccb.cam_ch.cam_func_code = XPT_SCSI_IO;
if (DataBuffer != NULL && DataBufferLength > 0)
{
ccb.cam_ch.cam_flags |= (Direction == Input) ?
CAM_DIR_IN : CAM_DIR_OUT;
uagt.uagt_buffer = (u_char *) DataBuffer;
uagt.uagt_buflen = DataBufferLength;
}
else
ccb.cam_ch.cam_flags |= CAM_DIR_NONE;
ccb.cam_ch.cam_flags |= CAM_DIS_AUTOSENSE;
ccb.cam_data_ptr = uagt.uagt_buffer;
ccb.cam_dxfer_len = uagt.uagt_buflen;
ccb.cam_timeout = 300; /* Timeout set to 5 minutes */
ccb.cam_sense_ptr = (u_char *) RequestSense;
ccb.cam_sense_len = sizeof(RequestSense_T);
ccb.cam_ch.cam_path_id = bus;
ccb.cam_ch.cam_target_id = target;
ccb.cam_ch.cam_target_lun = lun;
if (ioctl(DeviceFD, UAGT_CAM_IO, (caddr_t) &uagt) < 0)
{
return -1;
}
/* Check return status */
if ((ccb.cam_ch.cam_status & CAM_STATUS_MASK) != CAM_REQ_CMP)
{
if (ccb.cam_ch.cam_status & CAM_SIM_QFRZN)
{
(void) memset(&ccb, 0, sizeof(ccb));
(void) memset(&uagt, 0, sizeof(uagt));
/* Setup the user agent ccb */
uagt.uagt_ccb = (CCB_HEADER *) &ccb;
uagt.uagt_ccblen = sizeof(CCB_RELSIM);
/* Setup the scsi ccb */
ccb.cam_ch.my_addr = (struct ccb_header *) &ccb;
ccb.cam_ch.cam_ccb_len = sizeof(CCB_RELSIM);
ccb.cam_ch.cam_func_code = XPT_REL_SIMQ;
ccb.cam_ch.cam_path_id = bus;
ccb.cam_ch.cam_target_id = target;
ccb.cam_ch.cam_target_lun = lun;
if (ioctl(DeviceFD, UAGT_CAM_IO, (caddr_t) &uagt) < 0)
return -1;
}
printf( "mtx: %s:\n%s=0x%x %s=0x%x\n",
"SCSI command fault",
"Opcode",
CDB[0],
"Status",
ccb.cam_scsi_status);
return -1;
}
return 0;
}