📄 scsi2lib.c
字号:
/* initialize wide / sync support for each target to be FALSE */ pScsiTarget->wideSupport = FALSE; pScsiTarget->syncSupport = FALSE; scsiTargetReset (pScsiCtrl, busId); }/********************************************************************************* scsiTargetReset - reset the state of a SCSI target** Reset the target's state variables, but do not change its configurable* parameters. Typically called when a target is initialised, and when a* SCSI bus reset occurs.** RETURNS: N/A** NOMANUAL*/VOID scsiTargetReset ( FAST SCSI_CTRL *pScsiCtrl, /* ptr to SCSI controller info */ UINT busId /* SCSI bus ID of target to reset */ ) { FAST SCSI_TARGET *pScsiTarget = &pScsiCtrl->targetArr [busId]; /* intialise synchronous transfer fsm */ scsiSyncXferNegotiate (pScsiCtrl, pScsiTarget, SYNC_XFER_RESET); /* similarly, intialise the wide data transfer fsm */ scsiWideXferNegotiate (pScsiCtrl, pScsiTarget, WIDE_XFER_RESET); }/********************************************************************************* scsiTargetOptionsSet - set options for one or all SCSI targets** This routine sets the options defined by the bitmask `which' for the* specified target (or all targets if `devBusId' is SCSI_SET_OPT_ALL_TARGETS).** The bitmask `which' can be any combination of the following, bitwise* OR'd together (corresponding fields in the SCSI_OPTIONS structure are* shown in parentheses):** .TS* tab(|);* l l l.* SCSI_SET_OPT_TIMEOUT | 'selTimeOut' | select timeout period, microseconds* * SCSI_SET_OPT_MESSAGES | 'messages' | FALSE to disable SCSI messages** SCSI_SET_OPT_DISCONNECT | 'disconnect' | FALSE to disable discon/recon** SCSI_SET_OPT_XFER_PARAMS| 'maxOffset,' | max sync xfer offset, 0=>async* | 'minPeriod' | min sync xfer period, x 4 nsec.** SCSI_SET_OPT_TAG_PARAMS | 'tagType,' | default tag type (SCSI_TAG_*)* | 'maxTags' | max cmd tags available** SCSI_SET_OPT_WIDE_PARAMS| 'xferWidth' | data transfer width in bits** .TE** NOTE* This routine can be used after the target device has already been used; * in this case, however, it is not possible to change the tag parameters. * This routine must not be used while there is any SCSI activity on the * specified target(s).** RETURNS: OK, or ERROR if the bus ID or options are invalid.*/STATUS scsiTargetOptionsSet ( SCSI_CTRL *pScsiCtrl, /* ptr to SCSI controller info */ int devBusId, /* target to affect, or all */ SCSI_OPTIONS *pOptions, /* buffer containing new options */ UINT which /* which options to change */ ) { int i; /* verify bus ID of target, and validity of "which" bitmask */ if (((devBusId < SCSI_MIN_BUS_ID) || (devBusId > SCSI_MAX_BUS_ID)) && (devBusId != SCSI_SET_OPT_ALL_TARGETS)) { errnoSet (S_scsiLib_ILLEGAL_BUS_ID); return (ERROR); } if ((which & SCSI_SET_OPT_BITMASK) != which) { errnoSet (S_scsiLib_ILLEGAL_PARAMETER); return (ERROR); } /* set options for one or all targets (loop is easiest approach) */ for (i = 0; i < SCSI_MAX_TARGETS; ++i) { if ((devBusId == i) || (devBusId == SCSI_SET_OPT_ALL_TARGETS)) { SCSI_TARGET *pScsiTarget = &pScsiCtrl->targetArr [i]; /* support for variable select timeout period (us) */ if (which & SCSI_SET_OPT_TIMEOUT) pScsiTarget->selTimeOut = pOptions->selTimeOut; /* support for messages (other than COMMAND COMPLETE) */ if (which & SCSI_SET_OPT_MESSAGES) pScsiTarget->messages = pOptions->messages; /* support for disconnect / reconnect (requires messages) */ if (which & SCSI_SET_OPT_DISCONNECT) { if (pOptions->disconnect && (!pScsiCtrl->disconnect || !pScsiTarget->messages)) { errnoSet (S_scsiLib_ILLEGAL_PARAMETER); return (ERROR); } pScsiTarget->disconnect = pOptions->disconnect; } /* support for synchronous data transfer (requires messages) */ if (which & SCSI_SET_OPT_XFER_PARAMS) { if ((pOptions->maxOffset != SCSI_SYNC_XFER_ASYNC_OFFSET) && (!pScsiCtrl->syncXfer || !pScsiTarget->messages)) { errnoSet (S_scsiLib_ILLEGAL_PARAMETER); return (ERROR); } pScsiTarget->maxOffset = pOptions->maxOffset; pScsiTarget->minPeriod = pOptions->minPeriod; /* re-intialise synchronous transfer fsm */ scsiSyncXferNegotiate (pScsiCtrl, pScsiTarget, SYNC_XFER_RESET); } /* support for tagged commands (requires messages) */ if (which & SCSI_SET_OPT_TAG_PARAMS) { BOOL valid; switch (pOptions->tagType) { case SCSI_TAG_UNTAGGED: valid = (pOptions->maxTags == 0); break; case SCSI_TAG_SIMPLE: case SCSI_TAG_ORDERED: case SCSI_TAG_HEAD_OF_Q: valid = pScsiTarget->messages && (pOptions->maxTags > 0) && (pOptions->maxTags <= SCSI_MAX_TAGS); break; default: valid = FALSE; break; } if (!valid) { errnoSet (S_scsiLib_ILLEGAL_PARAMETER); return (ERROR); } pScsiTarget->tagType = pOptions->tagType; pScsiTarget->maxTags = pOptions->maxTags; } /* support for wide data transfer */ if (which & SCSI_SET_OPT_WIDE_PARAMS) { if (!pScsiCtrl->wideXfer || ( pOptions->xferWidth != SCSI_WIDE_XFER_SIZE_NARROW && pOptions->xferWidth != SCSI_WIDE_XFER_SIZE_DEFAULT ) ) { errnoSet (S_scsiLib_ILLEGAL_PARAMETER); return (ERROR); } pScsiTarget->xferWidth = pOptions->xferWidth; /* re-initialise wide data xfer fsm */ scsiWideXferNegotiate (pScsiCtrl, pScsiTarget, WIDE_XFER_RESET); } } } return (OK); }/********************************************************************************* scsiTargetOptionsGet - get options for one or all SCSI targets** This routine copies the current options for the specified target into the* caller's buffer.** RETURNS: OK, or ERROR if the bus ID is invalid.*/STATUS scsiTargetOptionsGet ( SCSI_CTRL *pScsiCtrl, /* ptr to SCSI controller info */ int devBusId, /* target to interrogate */ SCSI_OPTIONS *pOptions /* buffer to return options */ ) { SCSI_TARGET *pScsiTarget; if ((devBusId < SCSI_MIN_BUS_ID) || (devBusId > SCSI_MAX_BUS_ID)) { errnoSet (S_scsiLib_ILLEGAL_BUS_ID); return (ERROR); } pScsiTarget = &pScsiCtrl->targetArr [devBusId]; pOptions->selTimeOut = pScsiTarget->selTimeOut; pOptions->messages = pScsiTarget->messages; pOptions->disconnect = pScsiTarget->disconnect; pOptions->maxOffset = pScsiTarget->maxOffset; pOptions->minPeriod = pScsiTarget->minPeriod; pOptions->tagType = pScsiTarget->tagType; pOptions->maxTags = pScsiTarget->maxTags; pOptions->xferWidth = pScsiTarget->xferWidth; return (OK); }/********************************************************************************* scsi2PhysDevDelete - delete a SCSI physical device structure** This routine deletes a specified SCSI physical device structure.** RETURNS: OK, or ERROR if `pScsiPhysDev' is NULL or SCSI_BLK_DEVs have* been created on the device.*/LOCAL STATUS scsi2PhysDevDelete ( FAST SCSI_PHYS_DEV *pScsiPhysDev /* ptr to SCSI physical device info */ ) { FAST SCSI_CTRL *pScsiCtrl; if ((pScsiPhysDev == (SCSI_PHYS_DEV *) NULL) || (lstCount (&pScsiPhysDev->blkDevList) != 0) || (lstCount (&pScsiPhysDev->activeThreads) != 0) || (lstCount (&pScsiPhysDev->waitingThreads) != 0)) return (ERROR); pScsiCtrl = pScsiPhysDev->pScsiCtrl; pScsiCtrl->physDevArr [(pScsiPhysDev->pScsiTarget->scsiDevBusId << 3) | pScsiPhysDev->scsiDevLUN] = (SCSI_PHYS_DEV *) NULL; if (pScsiPhysDev->pReqSenseData != NULL) (void) free ((char *) pScsiPhysDev->pReqSenseData); if (pScsiPhysDev->pTagInfo != 0) (void) free ((char *) pScsiPhysDev->pTagInfo); if (pScsiPhysDev->mutexSem != 0) (void) semDelete (pScsiPhysDev->mutexSem); (void) free ((char *) pScsiPhysDev); return (OK); }/********************************************************************************* scsi2PhysDevCreate - create a SCSI physical device structure** This routine enables access to a SCSI device and must be invoked first.* It should be called once for each physical device on the SCSI bus.** If `reqSenseLength' is specified as NULL (0), one or more REQUEST_SENSE* commands are issued to the device to determine the number of bytes of* sense data it typically returns. Note that if the device returns variable* amounts of sense data depending on its state, consult the device manual * to determine the maximum amount of sense data that can be returned.** An INQUIRY command is issued to determine information about the device* including its type, make and model number, and its ability to accept* SCSI-2 features such as tagged commands. The scsiShow() routine displays* this information.** If `numBlocks' or `blockSize' are specified as NULL (0), a READ_CAPACITY* command is issued to determine those values. This will occur* only for device types which support READ_CAPACITY.** RETURNS: A pointer to the created SCSI_PHYS_DEV structure, or NULL if the* routine is unable to create the physical device structure.** NOTE: the `devType' and `removable' arguments are ignored.*/LOCAL SCSI_PHYS_DEV *scsi2PhysDevCreate ( 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 */ ) { SCSI_PHYS_DEV *pScsiPhysDev; /* ptr to SCSI physical dev. struct */ SCSI_TARGET *pScsiTarget; /* ptr to SCSI target structure */ /* REQ SENSE data for auto-sizing */ UINT8 reqSenseData [REQ_SENSE_ADD_LENGTH_BYTE + 1]; UINT8 inquiryData [DEFAULT_INQUIRY_DATA_LENGTH]; /* check bus ID and LUN are within limits */ if ((devBusId < SCSI_MIN_BUS_ID) || (devBusId > SCSI_MAX_BUS_ID) || (devLUN < SCSI_MIN_LUN) || (devLUN > SCSI_MAX_LUN)) { errnoSet (S_scsiLib_ILLEGAL_PARAMETER); return ((SCSI_PHYS_DEV *) NULL); } /* Check if this device was already created */ if (scsiPhysDevIdGet (pScsiCtrl, devBusId, devLUN) != NULL) { errnoSet (S_scsiLib_DEVICE_EXIST); return ((SCSI_PHYS_DEV *) NULL); } /* create a SCSI physical device structure */ pScsiPhysDev = (SCSI_PHYS_DEV *) calloc (1, sizeof (*pScsiPhysDev)); if (pScsiPhysDev == NULL) return ((SCSI_PHYS_DEV *) NULL); /* create device mutual exclusion semaphore */ if ((pScsiPhysDev->mutexSem = semMCreate (scsiPhysDevMutexOptions)) == NULL) { SCSI_DEBUG_MSG ("scsiPhysDevCreate: semMCreate of mutexSem failed.\n", 0, 0, 0, 0, 0, 0); goto failed; } /* initialize miscellaneous fields in the SCSI_PHYS_DEV struct */ pScsiTarget = &pScsiCtrl->targetArr [devBusId]; pScsiPhysDev->pScsiCtrl = pScsiCtrl; pScsiPhysDev->pScsiTarget = pScsiTarget; pScsiPhysDev->scsiDevLUN = devLUN; pScsiCtrl->physDevArr [(devBusId << 3) | devLUN] = pScsiPhysDev; /* initialize block device list */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -