📄 scsi1lib.c
字号:
/* scsi1Lib.c - Small Computer System Interface (SCSI) library (SCSI-1) *//* Copyright 1989-1994 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------02e,09jul97,dgp doc: correct fonts per SPR 785302d,29oct96,dgp doc: editing for newly published SCSI libraries02c,06may96,jds and more doc fixes...02b,01may96,jds yet more doc fixes...02a,13nov95,jds more doc tweaks01z,08nov95,jds doc tweaks01y,10oct94,jds fixed for SCSI1 and SCSI2 backward compatability01x,28feb93,jdi doc: changed comment in scsiWrtSecs() from "read" to "write".01w,27nov92,jdi documentation cleanup, including SPR 1415.01v,15sep92,ccc reworked select timeout, fixed extended message to work with new drive, documentation changes.01u,10aug92,ccc added timeouts to scsiXaction for each scsi command.01t,28jul92,rrr fixed decl of scsiSyncTarget01s,22jul92,gae added correct number of parameters to logMsg().01r,20jul92,eve Remove conditional INCLUDE_SYNC_SCSI compilation.01q,18jul92,smb Changed errno.h to errnoLib.h.01p,13jul92,eve added init of the current pScsiXaction in scsiPhaseSequence().01o,08jul92,eve supplies a reqSense buffer if there is no user buffer in scsiTransact routine.01n,03jul92,eve added new sync feature with NOMANUAL01m,26may92,rrr the tree shuffle01l,16dec91,gae added includes for ANSI; added parameters to logMsg() calls.01k,19nov91,rrr shut up some ansi warnings.01j,04oct91,rrr passed through the ansification filter -changed functions to ansi style -changed READ, WRITE and UPDATE to O_RDONLY O_WRONLY and ... -changed VOID to void -changed copyright notice01i,13mar91,jcc misc. clean-up and enhancements.01h,25oct90,jcc lint.01g,18oct90,jcc removed call to printErrno() in scsiAutoConfig().01f,02oct90,jcc UTINY became UINT8; added scsiAutoConfig(), scsiPhysDevIdGet(), and scsiIoctl() option FIODISKFORMAT; changed all malloc()'s to calloc()'s in xxCreate() routines; made changes associated with SEM_ID's becoming SEMAPHORE's in created structures; enhanced scsiPhysDevCreate() to determine amount and type of REQUEST SENSE data returned by the device; miscellaneous.01e,10aug90,dnw fixed warnings caused by changing scsiBusReset to VOIDFUNCPTR.01d,18jul90,jcc made semTake() calls 5.0 compatible; clean-up.01c,08jun90,jcc modified incoming message handling; generalized scsiTransact calls to a procedure variable to allow off-board SCSI controller drivers; documentation.01b,23mar90,jcc lint.01a,05may89,jcc written.*//*DESCRIPTIONThis library implements the Small Computer System Interface (SCSI)protocol in a controller-independent manner. It implements only the SCSIinitiator function; the library does not support a VxWorks targetacting as a SCSI target. Furthermore, in the current implementation, aVxWorks target is assumed to be the only initiator on the SCSI bus,although there may be multiple targets (SCSI peripherals) on the bus.The implementation is transaction based. A transaction is defined as theselection of a SCSI device by the initiator, the issuance of a SCSI command,and the sequence of data, status, and message phases necessary to performthe command. A transaction normally completes with a "Command Complete" message fromthe target, followed by disconnection from the SCSI bus. Ifthe status from the target is "Check Condition," the transaction continues;the initiator issues a "Request Sense" command to gain more informationon the exception condition reported.Many of the subroutines in scsi1Lib facilitate the transaction offrequently used SCSI commands. Individual command fields are passed asarguments from which SCSI Command Descriptor Blocks are constructed, andfields of a SCSI_TRANSACTION structure are filled in appropriately. Thisstructure, along with the SCSI_PHYS_DEV structure associated with thetarget SCSI device, is passed to the routine whose address is indicated bythe 'scsiTransact' field of the SCSI_CTRL structure associated with therelevant SCSI controller.The function variable 'scsiTransact' is set by the individual SCSIcontroller driver. For off-board SCSI controllers, thisroutine rearranges the fields of the SCSI_TRANSACTION structure intothe appropriate structure for the specified hardware, which then carries outthe transaction through firmware control. Drivers for an on-boardSCSI-controller chip can use the scsiTransact() routine in scsiLib (whichinvokes the scsi1Transact() routine in scsi1Lib), as long as they provide the other functions specified in the SCSI_CTRL structure.Note that no disconnect/reconnect capability is currently supported.SUPPORTED SCSI DEVICESThe scsi1Lib library supports use of SCSI peripherals conforming to the standards specified in .I "Common Command Set (CCS) of the SCSI, Rev. 4.B."Most SCSI peripherals currently offered support CCS. While an attempt has been madeto have scsi1Lib support non-CCS peripherals, not all commands or featuresof this library are guaranteed to work with them. For example,auto-configuration may be impossible with non-CCS devices, if they do notsupport the INQUIRY command.Not all classes of SCSI devices are supported. However, the scsiLib libraryprovides the capability to transact any SCSI command on any SCSI devicethrough the FIOSCSICOMMAND function of the scsiIoctl() routine.Only direct-access devices (disks) are supported by a file system. Forother types of devices, additional, higher-level software is necessary tomap user-level commands to SCSI transactions.CONFIGURING SCSI CONTROLLERSThe routines to create and initialize a specific SCSI controller areparticular to the controller and normally are found in its librarymodule. The normal calling sequence is:.ne 4.CS xxCtrlCreate (...); /@ parameters are controller specific @/ xxCtrlInit (...); /@ parameters are controller specific @/.CEThe conceptual difference between the two routines is that xxCtrlCreate()calloc's memory for the xx_SCSI_CTRL data structure and initializesinformation that is never expected to change (for example, clock rate). Theremaining fields in the xx_SCSI_CTRL structure are initialized byxxCtrlInit() and any necessary registers are written on the SCSIcontroller to effect the desired initialization. Thisroutine can be called multiple times, although this is rarely required.For example, the bus ID of the SCSIcontroller can be changed without rebooting the VxWorks system.CONFIGURING PHYSICAL SCSI DEVICESBefore a device can be used, it must be "created," that is, declared.This is done with scsiPhysDevCreate() and can only be done after aSCSI_CTRL structure exists and has been properly initialized..CSSCSI_PHYS_DEV *scsiPhysDevCreate ( SCSI_CTRL * pScsiCtrl,/@ ptr to SCSI controller info @/ int devBusId, /@ device's SCSI bus ID @/ int devLUN, /@ device's logical unit number @/ int reqSenseLength, /@ length of REQUEST SENSE data dev returns @/ int devType, /@ type of SCSI device @/ BOOL removable, /@ whether medium is removable @/ int numBlocks, /@ number of blocks on device @/ int blockSize /@ size of a block in bytes @/ ).CESeveral of these parameters can be left unspecified, as follows:.iP <reqSenseLength>If 0, issue a REQUEST_SENSE to determine a request sense length..iP <devType>If -1, issue an INQUIRY to determine the device type..iP "<numBlocks>, <blockSize>"If 0, issue a READ_CAPACITY to determine the number of blocks..LPThe above values are recommended, unless the device does not support therequired commands, or other non-standard conditions prevail.LOGICAL PARTITIONS ON BLOCK DEVICESIt is possible to have more than one logical partition on a SCSI blockdevice. This capability is currently not supported for removable mediadevices. A partition is an array of contiguously addressed blockswith a specified starting block address and a specified number of blocks.The scsiBlkDevCreate() routine is called once for each block devicepartition. Under normal usage, logical partitions should not overlap..ne 8.CSSCSI_BLK_DEV *scsiBlkDevCreate ( SCSI_PHYS_DEV * pScsiPhysDev, /@ ptr to SCSI physical device info @/ int numBlocks, /@ number of blocks in block device @/ int blockOffset /@ address of first block in volume @/ ).CENote that if <numBlocks> is 0, the rest of the device is used.ATTACHING FILE SYSTEMS TO LOGICAL PARTITIONSFiles cannot be read or written to a disk partition until a file system(such as dosFs or rt11Fs) has been initialized on the partition. For moreinformation, see the documentation in dosFsLib or rt11FsLib.TRANSMITTING ARBITRARY COMMANDS TO SCSI DEVICESThe scsi1Lib library provides routines that implement many common SCSIcommands. Still, there are situations that require commands that are notsupported by scsi1Lib (for example, writing software to control non-direct access devices). Arbitrary commands are handled with the FIOSCSICOMMAND option to scsiIoctl(). The <arg> parameter for FIOSCSICOMMAND is a pointer to a valid SCSI_TRANSACTION structure. Typically, a call to scsiIoctl() is written as a subroutine of the form:.CSSTATUS myScsiCommand ( SCSI_PHYS_DEV * pScsiPhysDev, /@ ptr to SCSI physical device @/ char * buffer, /@ ptr to data buffer @/ int bufLength, /@ length of buffer in bytes @/ int someParam /@ param. specifiable in cmd block @/ ) { SCSI_COMMAND myScsiCmdBlock; /@ SCSI command byte array @/ SCSI_TRANSACTION myScsiXaction; /@ info on a SCSI transaction @/ /@ fill in fields of SCSI_COMMAND structure @/ myScsiCmdBlock [0] = MY_COMMAND_OPCODE; /@ the required opcode @/ . myScsiCmdBlock [X] = (UINT8) someParam; /@ for example @/ . myScsiCmdBlock [N-1] = MY_CONTROL_BYTE; /@ typically == 0 @/ /@ fill in fields of SCSI_TRANSACTION structure @/ myScsiXaction.cmdAddress = myScsiCmdBlock; myScsiXaction.cmdLength = <# of valid bytes in myScsiCmdBlock>; myScsiXaction.dataAddress = (UINT8 *) buffer; myScsiXaction.dataDirection = <O_RDONLY (0) or O_WRONLY (1)>; myScsiXaction.dataLength = bufLength; myScsiXaction.cmdTimeout = timeout in usec; /@ if dataDirection is O_RDONLY, and the length of the input data is * variable, the following parameter specifies the byte # (min == 0) * of the input data which will specify the additional number of * bytes available @/ myScsiXaction.addLengthByte = X; if (scsiIoctl (pScsiPhysDev, FIOSCSICOMMAND, &myScsiXaction) == OK) return (OK); else /@ optionally perform retry or other action based on value of * myScsiXaction.statusByte @/ return (ERROR); }.CEINCLUDE FILESscsiLib.h, scsi1Lib.hSEE ALSO: dosFsLib, rt11FsLib,.I "American National Standards for Information Systems - Small Computer" .I "System Interface (SCSI), ANSI X3.131-1986,".pG "I/O System, Local File Systems"*/#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"/* forward static functions */LOCAL BOOL strIsPrintable (char *);LOCAL STATUS scsiDevSelect (SCSI_PHYS_DEV *, SCSI_TRANSACTION *);LOCAL STATUS scsiStatusCheck (BLK_DEV *);LOCAL STATUS scsiPhaseSequence (SCSI_PHYS_DEV *, SCSI_TRANSACTION *);LOCAL STATUS scsiBlkDevIoctl (SCSI_BLK_DEV *, int, int);LOCAL STATUS scsiSyncTarget (SCSI_PHYS_DEV *, int, int, SCSI_SYNC_AGREEMENT *);LOCAL STATUS scsi1CtrlInit (SCSI_CTRL *);LOCAL STATUS scsi1TestUnitRdy (SCSI_PHYS_DEV *);LOCAL SCSI_PHYS_DEV * scsi1PhysDevIdGet (SCSI_CTRL *, int, int);LOCAL STATUS scsi1ReqSense (SCSI_PHYS_DEV *, char *, int);LOCAL STATUS scsi1Inquiry (SCSI_PHYS_DEV *, char *, int);LOCAL STATUS scsi1ReadCapacity (SCSI_PHYS_DEV *, int *, int *);LOCAL STATUS scsi1RdSecs (SCSI_BLK_DEV *, int, int, char *);LOCAL STATUS scsi1WrtSecs (SCSI_BLK_DEV *, int, int, char *);LOCAL STATUS scsi1PhysDevDelete (FAST SCSI_PHYS_DEV *);LOCAL SCSI_PHYS_DEV * scsi1PhysDevCreate (SCSI_CTRL *, int, int, int, int, BOOL, int, int);LOCAL STATUS scsi1AutoConfig (SCSI_CTRL *);LOCAL BLK_DEV * scsi1BlkDevCreate (SCSI_PHYS_DEV *, int, int);LOCAL void scsi1BlkDevInit (SCSI_BLK_DEV *, int, int);LOCAL void scsi1BlkDevShow (SCSI_PHYS_DEV *);LOCAL STATUS scsi1Show (FAST SCSI_CTRL *);LOCAL STATUS scsi1BusReset (SCSI_CTRL *);LOCAL STATUS scsi1CmdBuild (SCSI_COMMAND, int *, UINT8, int, BOOL, int, int, UINT8);LOCAL STATUS scsi1Transact (SCSI_PHYS_DEV *, SCSI_TRANSACTION *);LOCAL STATUS scsi1Ioctl (SCSI_PHYS_DEV *, int, int);LOCAL STATUS scsi1FormatUnit (SCSI_PHYS_DEV *, BOOL, int, int, int, char *,int);LOCAL STATUS scsi1ModeSelect (SCSI_PHYS_DEV *, int, int, char *, int);LOCAL STATUS scsi1ModeSense (SCSI_PHYS_DEV *, int, int, char *, int);LOCAL char * scsi1PhaseNameGet (int);SCSI_FUNC_TBL scsi1IfTbl = { (FUNCPTR) scsi1CtrlInit, (FUNCPTR) scsi1BlkDevInit, (FUNCPTR) scsi1BlkDevCreate, (FUNCPTR) scsi1BlkDevShow, (FUNCPTR) scsi1PhaseNameGet, (FUNCPTR) scsi1PhysDevCreate, (FUNCPTR) scsi1PhysDevDelete, (FUNCPTR) scsi1PhysDevIdGet, (FUNCPTR) scsi1AutoConfig, (FUNCPTR) scsi1Show, (FUNCPTR) scsi1BusReset, (FUNCPTR) scsi1CmdBuild, (FUNCPTR) scsi1Transact, (FUNCPTR) scsi1Ioctl, (FUNCPTR) scsi1FormatUnit, (FUNCPTR) scsi1ModeSelect, (FUNCPTR) scsi1ModeSense, (FUNCPTR) scsi1ReadCapacity, (FUNCPTR) scsi1RdSecs, (FUNCPTR) scsi1WrtSecs, (FUNCPTR) scsi1TestUnitRdy, (FUNCPTR) scsi1Inquiry, (FUNCPTR) scsi1ReqSense };/********************************************************************************* scsi1IfInit - initialize the SCSI1 interface to scsiLib** NOMANUAL */void scsi1IfInit () { pScsiIfTbl = &scsi1IfTbl; pScsiIfTbl->scsiCtrlInit = (FUNCPTR) scsi1CtrlInit; pScsiIfTbl->scsiPhysDevDelete = (FUNCPTR) scsi1PhysDevDelete; pScsiIfTbl->scsiPhysDevCreate = (FUNCPTR) scsi1PhysDevCreate; pScsiIfTbl->scsiAutoConfig = (FUNCPTR) scsi1AutoConfig; pScsiIfTbl->scsiBlkDevCreate = (FUNCPTR) scsi1BlkDevCreate; pScsiIfTbl->scsiPhysDevIdGet = (FUNCPTR) scsi1PhysDevIdGet; pScsiIfTbl->scsiBlkDevInit = (FUNCPTR) scsi1BlkDevInit; pScsiIfTbl->scsiBlkDevShow = (FUNCPTR) scsi1BlkDevShow; pScsiIfTbl->scsiShow = (FUNCPTR) scsi1Show; pScsiIfTbl->scsiBusReset = (FUNCPTR) scsi1BusReset; pScsiIfTbl->scsiCmdBuild = (FUNCPTR) scsi1CmdBuild; pScsiIfTbl->scsiTransact = (FUNCPTR) scsi1Transact; pScsiIfTbl->scsiIoctl = (FUNCPTR) scsi1Ioctl; pScsiIfTbl->scsiFormatUnit = (FUNCPTR) scsi1FormatUnit; pScsiIfTbl->scsiModeSelect = (FUNCPTR) scsi1ModeSelect; pScsiIfTbl->scsiModeSense = (FUNCPTR) scsi1ModeSense; pScsiIfTbl->scsiPhaseNameGet = (FUNCPTR) scsi1PhaseNameGet; pScsiIfTbl->scsiReadCapacity = (FUNCPTR) scsi1ReadCapacity; pScsiIfTbl->scsiRdSecs = (FUNCPTR) scsi1RdSecs; pScsiIfTbl->scsiWrtSecs = (FUNCPTR) scsi1WrtSecs; pScsiIfTbl->scsiTestUnitRdy = (FUNCPTR) scsi1TestUnitRdy; pScsiIfTbl->scsiInquiry = (FUNCPTR) scsi1Inquiry; pScsiIfTbl->scsiReqSense = (FUNCPTR) scsi1ReqSense; }/********************************************************************************* scsi1CtrlInit - initialize generic fields of a SCSI_CTRL structure** This routine should be called by the SCSI controller libraries' xxCtrlCreate* routines, which are responsible for initializing any fields not herein* initialized. It is NOT intended to be called directly by a user.** NOTE* As a matter of good practice, the SCSI_CTRL structure should be* calloc()'ed by the xxCtrlCreate() routine, so that all fields are* initially zero. If this is done, some of the work of this routine will be* redundant.** RETURNS: OK, or ERROR if a semaphore initialization fails.** NOMANUAL*/LOCAL STATUS scsi1CtrlInit ( SCSI_CTRL *pScsiCtrl /* ptr to SCSI_CTRL struct to initialize */ ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -