?? scsiseqlib.c
字號:
/* scsiSeqLib.c - SCSI sequential access device library (SCSI-2) *//* Copyright 1989-1994 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------02k,21feb99,jdi doc: listed errnos.02j,09jul97,dgp doc: correct fonts per SPR 785302i,06mar97,dds SPR 8120: fixed scsiRdTape to return the actual number of bytes or blocks read, 0 if end of file, or ERROR.02h,29oct96,dgp doc: editing for newly published SCSI libraries02g,16sep96,dds removed compiler warnings.02f,23jul96,dds SPR 6718: added support for tranfers above 16 MB.02e,06may96,jds more doc tweaks02d,01may96,jds doc tweaks02c,20sep95,jds changed scsiStatusCheck to scsiSeqStatusCheck and made it global02b,26jul95,jds maxVarBlockLimit to be set by scsiPhysDevCreate (Wrt & Rd) 02a,10may95,jds reworked for use with enhanced SCSI-2 library; added tagType, and priority ; removed the idea of retrying command upon UNIT_ATTENTION which should be managed by higher level layer.01e,28jun94,ccc doc tweaks.01d,21jun94,ccc changed dataAddress from NONE to NULL.01c,27apr94,jdi doc tweaks.01b,20apr94,jds enhanced scsiWrtTape and scsiRdTape to correctly handle fixed block transfers and variable block transfers with maxBlockLimit01a,24jan94,ccc created to support sequential access SCSI devices.*//*DESCRIPTIONThis library contains commands common to all sequential-access SCSI devices.Sequential-access SCSI devices are usually SCSI tape devices.These routines are separated from scsi2Lib in order to create an additionallayer for better support of all SCSI sequential devices.SCSI commands in this library include:.TStab(|);lf3 lf3l l.Command | Op Code_ERASE | (0x19)MODE SELECT (6) | (0x15)MODE_SENSE (6) | (0x1a)READ (6) | (0x08)READ BLOCK LIMITS | (0x05)RELEASE UNIT | (0x17)RESERVE UNIT | (0x16)REWIND | (0x01)SPACE | (0x11)WRITE (6) | (0x0a)WRITE FILEMARKS | (0x10)LOAD/UNLOAD | (0x1b).TEThe SCSI routines implemented here operate mostly on a SCSI_SEQ_DEVstructure. This structure acts as an interface between this libraryand a higher-level layer. The SEQ_DEV structure is analogous to theBLK_DEV structure for block devices. The scsiSeqDevCreate() routine creates a SCSI_SEQ_DEV structure whose first element is a SEQ_DEV, operated upon by higher layers. This routine publishesall functions to be invoked byhigher layers and maintains some state information (for example, block size)for tracking SCSI-sequential-device information.INCLUDE FILESscsiLib.h, scsi2Lib.hSEE ALSO: tapeFsLib, scsi2Lib,.pG "I/O System, Local File Systems"*/#define INCLUDE_SCSI2#include "vxWorks.h"#include "ioLib.h"#include "ctype.h"#include "stdlib.h"#include "errnoLib.h"#include "taskLib.h"#include "logLib.h"#include "string.h"#include "stdio.h"#include "scsiLib.h"#include "sysLib.h"#define MODE_BUF_LENGTH 0xff#define SCSI_MAX_XFER_BLOCKS 0xffffff#define SCSI_READ 0x00#define SCSI_WRITE 0x01/* globals */IMPORT BOOL scsiDebug; /* enable task level debug messages */IMPORT BOOL scsiIntsDebug; /* enable int level debug messages *//* select timeout to use when creating a SCSI_PHYS_DEV */IMPORT UINT32 scsiSelectTimeout;IMPORT SCSI_CTRL *pSysScsiCtrl; /* ptr to default SCSI_CTRL struct */LOCAL VOID scsiXactionFill (SCSI_TRANSACTION *, SCSI_COMMAND, BOOL, int, UINT, int, UINT8 *);LOCAL VOID scsiCmdFill (SCSI_SEQ_DEV *, SCSI_COMMAND , BOOL, BOOL, int);LOCAL int scsiRdTapeFixedBlocks (SCSI_SEQ_DEV *, UINT, char * );LOCAL int scsiRdTapeVariableBlocks (SCSI_SEQ_DEV *, UINT, char * );LOCAL int scsiCalcDataRead (SCSI_SEQ_DEV *, UINT);/********************************************************************************* scsiSeqDevCreate - create a SCSI sequential device** This routine creates a SCSI sequential device and saves a pointer to this* SEQ_DEV in the SCSI physical device. The following functions are* initialized in this structure:** .TS* tab(|);* l l.* sd_seqRd | - scsiRdTape()* sd_seqWrt | - scsiWrtTape()* sd_ioctl | - scsiIoctl() (in scsiLib)* sd_seqWrtFileMarks | - scsiWrtFileMarks()* sd_statusChk | - scsiSeqStatusCheck()* sd_reset | - (not used)* sd_rewind | - scsiRewind()* sd_reserve | - scsiReserve()* sd_release | - scsiRelease()* sd_readBlkLim | - scsiSeqReadBlockLimits()* sd_load | - scsiLoadUnit()* sd_space | - scsiSpace()* sd_erase | - scsiErase()* .TE** Only one SEQ_DEV per SCSI_PHYS_DEV is allowed, unlike BLK_DEVs where an * entire list is maintained. Therefore, this routine can be called only * once per creation of a sequential device.** RETURNS: A pointer to the SEQ_DEV structure, or NULL if the command fails. * */SEQ_DEV *scsiSeqDevCreate ( SCSI_PHYS_DEV *pScsiPhysDev /* ptr to SCSI physical device info */ ) { SCSI_SEQ_DEV *pScsiSeqDev; /* ptr to SCSI sequential dev struct */ /* check parameter for validity */ if (pScsiPhysDev == NULL) { errnoSet (S_scsiLib_ILLEGAL_PARAMETER); SCSI_DEBUG_MSG ("scsiSeqDevCreate: Invalid input parameter(s).\n", 0, 0, 0, 0, 0, 0); return ((SEQ_DEV *) NULL); } /* Check if sequential device alread exists */ if (pScsiPhysDev->pScsiSeqDev != NULL) { errnoSet (S_scsiLib_ILLEGAL_OPERATION); SCSI_DEBUG_MSG ("scsiSeqDevCreate: SEQ_DEV already exists.\n", 0, 0, 0, 0, 0, 0); return ((SEQ_DEV *) NULL); } /* return NULL if not a sequential access device */ if (pScsiPhysDev->scsiDevType != SCSI_DEV_SEQ_ACCESS) { errnoSet (S_scsiLib_ILLEGAL_OPERATION); SCSI_DEBUG_MSG ("scsiSeqDevCreate:", 0, 0, 0, 0, 0, 0); SCSI_DEBUG_MSG ("Physical device is not a sequential device.\n", 0, 0, 0, 0, 0, 0); return ((SEQ_DEV *) NULL); } if (!pScsiPhysDev->removable) SCSI_DEBUG_MSG ("scsiSeqDevCreate: Odd! Non removable tape!!\n", 0, 0, 0, 0, 0, 0); pScsiSeqDev = (SCSI_SEQ_DEV *) calloc (1, sizeof (SCSI_SEQ_DEV)); if (pScsiSeqDev == NULL) return ((SEQ_DEV *) NULL); pScsiSeqDev->seqDev.sd_seqRd = (FUNCPTR) scsiRdTape; pScsiSeqDev->seqDev.sd_seqWrt = (FUNCPTR) scsiWrtTape; pScsiSeqDev->seqDev.sd_ioctl = (FUNCPTR) scsiIoctl; pScsiSeqDev->seqDev.sd_seqWrtFileMarks = (FUNCPTR) scsiWrtFileMarks; pScsiSeqDev->seqDev.sd_rewind = (FUNCPTR) scsiRewind; pScsiSeqDev->seqDev.sd_reserve = (FUNCPTR) scsiReserveUnit; pScsiSeqDev->seqDev.sd_release = (FUNCPTR) scsiReleaseUnit; pScsiSeqDev->seqDev.sd_readBlkLim = (FUNCPTR) scsiSeqReadBlockLimits; pScsiSeqDev->seqDev.sd_load = (FUNCPTR) scsiLoadUnit; pScsiSeqDev->seqDev.sd_space = (FUNCPTR) scsiSpace; pScsiSeqDev->seqDev.sd_erase = (FUNCPTR) scsiErase; pScsiSeqDev->seqDev.sd_statusChk = (FUNCPTR) scsiSeqStatusCheck; pScsiSeqDev->seqDev.sd_reset = (FUNCPTR) NULL; pScsiSeqDev->seqDev.sd_readyChanged = TRUE; pScsiSeqDev->pScsiPhysDev = pScsiPhysDev; pScsiPhysDev->pScsiSeqDev = pScsiSeqDev; /* Note: sd_blkSize and sd_mode are left uninitialized */ /* this should be the same as returning (SEQ_DEV *) pScsiSeqDev ?? */ return (&pScsiSeqDev->seqDev); } /********************************************************************************* scsiErase - issue an ERASE command to a SCSI device** This routine issues an ERASE command to a specified SCSI device.** RETURNS: OK, or ERROR if the command fails.*/STATUS scsiErase ( SCSI_PHYS_DEV *pScsiPhysDev, /* ptr to SCSI physical device */ BOOL longErase /* TRUE for entire tape erase */ ) { SCSI_COMMAND eraseCommand; /* SCSI command byte array */ SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */ STATUS status; /* status of transaction */ SCSI_DEBUG_MSG ("scsiErase:\n", 0, 0, 0, 0, 0, 0); /* * Build the SCSI command. Do not use scsiCmdBuild, because that function * is used only for direct access commands. */ eraseCommand[0] = SCSI_OPCODE_ERASE; eraseCommand[1] = (UINT8) ((pScsiPhysDev->scsiDevLUN & 0x7) << 5); if (longErase) eraseCommand [1] |= 0x01; /* set long bit */ eraseCommand[2] = (UINT8) 0; eraseCommand[3] = (UINT8) 0; eraseCommand[4] = (UINT8) 0; eraseCommand[5] = (UINT8) 0; scsiXaction.cmdAddress = eraseCommand; scsiXaction.cmdLength = SCSI_GROUP_0_CMD_LENGTH; scsiXaction.dataAddress = (UINT8 *) NULL; scsiXaction.dataDirection = O_WRONLY; scsiXaction.dataLength = 0; scsiXaction.addLengthByte = NULL; scsiXaction.cmdTimeout = SCSI_TIMEOUT_FULL; scsiXaction.tagType = SCSI_TAG_DEFAULT; scsiXaction.priority = SCSI_THREAD_TASK_PRIORITY; status = (*pScsiPhysDev->pScsiCtrl->scsiTransact) (pScsiPhysDev, &scsiXaction); return (status); }/********************************************************************************* scsiTapeModeSelect - issue a MODE_SELECT command to a SCSI tape device** This routine issues a MODE_SELECT command to a specified SCSI device.** RETURNS: OK, or ERROR if the command fails.*/STATUS scsiTapeModeSelect ( SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device */ int pageFormat, /* value of the page format bit (0-1) */ int saveParams, /* value of the save parameters bit (0-1) */ char *buffer, /* ptr to output data buffer */ int bufLength /* length of buffer in bytes */ ) { SCSI_COMMAND scsiCommand; /* SCSI command byte array */ SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */ STATUS status; /* status of transaction */ SCSI_DEBUG_MSG ("scsiTapeModeSelect:\n", 0, 0, 0, 0, 0, 0); scsiCommand[0] = SCSI_OPCODE_MODE_SELECT; scsiCommand[1] = (UINT8) ((pScsiPhysDev->scsiDevLUN & 0x7) << 5); scsiCommand[1] |= ((UINT8) ((pageFormat & 1) << 4) | (UINT8) (saveParams & 1)); scsiCommand[2] = (UINT8) 0; scsiCommand[3] = (UINT8) 0; scsiCommand[4] = (UINT8) (bufLength & 0xff); scsiCommand[5] = (UINT8) 0; scsiXaction.cmdAddress = scsiCommand; scsiXaction.cmdLength = SCSI_GROUP_0_CMD_LENGTH; scsiXaction.dataAddress = (UINT8 *) buffer; scsiXaction.dataDirection = O_WRONLY; scsiXaction.dataLength = min (0xff, bufLength); scsiXaction.addLengthByte = NULL; scsiXaction.cmdTimeout = SCSI_TIMEOUT_5SEC; scsiXaction.tagType = SCSI_TAG_DEFAULT; scsiXaction.priority = SCSI_THREAD_TASK_PRIORITY; status = (*pScsiPhysDev->pScsiCtrl->scsiTransact) (pScsiPhysDev, &scsiXaction); return (status); }/********************************************************************************* scsiTapeModeSense - issue a MODE_SENSE command to a SCSI tape device** This routine issues a MODE_SENSE command to a specified SCSI tape device.** RETURNS: OK, or ERROR if the command fails.*/STATUS scsiTapeModeSense ( SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device */ int pageControl, /* value of the page control field (0-3) */ int pageCode, /* value of the page code field (0-0x3f) */ char *buffer, /* ptr to input data buffer */ int bufLength /* length of buffer in bytes */ ) { SCSI_COMMAND scsiCommand; /* SCSI command byte array */ SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */ STATUS status; /* status of transaction */ SCSI_DEBUG_MSG ("scsiModeSense: cmdAddress 0x%x\n", (int) scsiCommand, 0, 0, 0, 0, 0); scsiCommand[0] = SCSI_OPCODE_MODE_SENSE; scsiCommand[1] = (UINT8) ((pScsiPhysDev->scsiDevLUN & 0x7) << 5); scsiCommand[2] = (UINT8) ((pageControl << 6) | pageCode); scsiCommand[3] = (UINT8) 0; scsiCommand[4] = (UINT8) (bufLength & 0xff); scsiCommand[5] = (UINT8) 0; scsiXaction.cmdAddress = scsiCommand; scsiXaction.cmdLength = SCSI_GROUP_0_CMD_LENGTH; scsiXaction.dataAddress = (UINT8 *) buffer; scsiXaction.dataDirection = O_RDONLY; scsiXaction.dataLength = min (0xff, bufLength); scsiXaction.addLengthByte = MODE_SENSE_ADD_LENGTH_BYTE; scsiXaction.cmdTimeout = SCSI_TIMEOUT_5SEC; scsiXaction.tagType = SCSI_TAG_DEFAULT; scsiXaction.priority = SCSI_THREAD_TASK_PRIORITY; status = (*pScsiPhysDev->pScsiCtrl->scsiTransact) (pScsiPhysDev, &scsiXaction); return (status); }/********************************************************************************* scsiReadBlockLimits - issue a READ_BLOCK_LIMITS command to a SCSI device** This routine issues a READ_BLOCK_LIMITS command to a specified SCSI device.** RETURNS: OK, or ERROR if the command fails.** NOMANUAL*/STATUS scsiReadBlockLimits ( SCSI_PHYS_DEV * pScsiPhysDev,/* ptr to SCSI physical device */ int *pMaxBlockLength, /* where to return maximum block length */ UINT16 *pMinBlockLength /* where to return minimum block length */ ) { SCSI_COMMAND readBlockLimitCommand; /* SCSI command byte array */ RD_BLOCK_LIMIT_DATA readBlkLimitData; /* data structure for results */ SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */ STATUS status; /* status of the transaction */ SCSI_DEBUG_MSG ("scsiReadBlockLimit:\n", 0, 0, 0, 0, 0, 0); readBlockLimitCommand[0] = SCSI_OPCODE_READ_BLOCK_LIMITS; readBlockLimitCommand[1] = (UINT8) ((pScsiPhysDev->scsiDevLUN & 0x7) << 5); readBlockLimitCommand[2] = (UINT8) 0; readBlockLimitCommand[3] = (UINT8) 0; readBlockLimitCommand[4] = (UINT8) 0; readBlockLimitCommand[5] = (UINT8) 0; scsiXaction.cmdAddress = readBlockLimitCommand; scsiXaction.cmdLength = SCSI_GROUP_0_CMD_LENGTH; scsiXaction.dataAddress = (UINT8 *) &readBlkLimitData; scsiXaction.dataDirection = O_RDONLY; scsiXaction.dataLength = sizeof (readBlkLimitData); scsiXaction.addLengthByte = NULL;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -