|
|
Sample Programs from NeXSTEP 3.3
/*
* SCSITape.m -- implementation of scsi tape driver routines
*
* HISTORY
* 31-Mar-93 Phillip Dibner at NeXT
* Created.
*
*/
#import <sys/errno.h>
#import <sys/types.h>
#import <sys/time.h>
#import <sys/conf.h>
#import <sys/uio.h>
#import <sys/mtio.h>
#import <bsd/dev/scsireg.h>
#import <driverkit/scsiTypes.h>
#import <driverkit/align.h>
#import <driverkit/kernelDriver.h>
#import <driverkit/scsiTypes.h>
#import <driverkit/return.h>
#import <machkit/NXLock.h>
#import <kernserv/prototypes.h>
#import <kernserv/kern_server_types.h>
#import "SCSITape.h"
#import "SCSITapeTypes.h"
#define DRIVE_TYPE_LENGTH 80
#define USE_EBD 1 /* use "even byte disconnect" rather than
* "no disconnect during data xfer" for exabyte
*/
extern int st_devsw_init();
static int moveString(); /* rmv nulls & blanks from inquiry strings */
void assign_cdb_c6s_len(); /* store length data in little-endian cdb_6s */
void assign_msbd_numblocks(); /* store nblks in little-endian modesel bd */
void assign_msbd_blocklength(); /* store blklen in little-endian modesel bd */
int cdb_c6s_len_value(); /* byte swap to read length data in cdb */
int er_info_value (); /* byte swapping for sense reply info data */
id stIdMap [NST];
@implementation SCSITape
+ (IODeviceStyle)deviceStyle
{
return IO_IndirectDevice;
}
/*
* The protocol we need as an indirect device.
*/
static Protocol *protocols[] = {
@protocol(IOSCSIControllerExported),
nil
};
+ (Protocol **)requiredProtocols
{
return protocols;
}
static unsigned int tapeUnit = 0;
+ (BOOL) probe: deviceDescription
{
SCSITape *tapeId = nil;
unsigned char stTarget, stLun;
id controllerId =
[deviceDescription directDevice];
stInitReturn_t irtn = STR_ERROR;
BOOL brtn = NO;
int major;
/* asm volatile("int3"); */ // Early break to debugger
if ((major = st_devsw_init()) < 0) {
return NO;
}
for (stTarget=0; stTarget<SCSI_NTARGETS; stTarget++) {
for(stLun=0; stLun<SCSI_NLUNS; stLun++) {
#ifdef DEBUG
IOLog ("SCSITape probe: target %d lun %d\n", stTarget, stLun);
#endif DEBUG
if(tapeId == nil) {
/*
* Create an instance, do some basic
* initialization. Set up a default
* device name for error reporting during
* initialization.
*/
tapeId = [SCSITape alloc];
}
if ([controllerId reserveTarget:stTarget
lun:stLun
forOwner:tapeId]) {
/*
* Someone already has this one.
*/
continue;
}
else {
[tapeId setReservedTargetLun: YES];
}
#ifdef DEBUG
IOLog ("SCSITape probe: about to init\n");
#endif DEBUG
irtn = [tapeId initSCSITape:(int)tapeUnit
target: stTarget
lun: stLun
controller: controllerId
majorDeviceNumber: major];
#ifdef DEBUG
IOLog ("SCSITape probe: irtn is %d\n", irtn);
#endif DEBUG
switch (irtn) {
case STR_GOOD:
/*
* Init'd OK - still must register device.
*/
[tapeId registerDevice];
stIdMap [tapeUnit] = tapeId;
tapeId = nil;
tapeUnit++;
if (tapeUnit >= NST) goto done;
brtn = YES;
break;
default:
[controllerId releaseTarget: stTarget
lun: stLun
forOwner: tapeId];
[tapeId setReservedTargetLun: NO];
if(irtn == STR_SELECTTO) {
/*
* Skip the rest of the luns on
* this target.
*/
goto nextTarget;
}
/*
* else try next lun.
*/
} /* switch (irtn) */
} /* for lun */
nextTarget:
continue;
} /* for target */
done:
/*
* Free up leftover owner and id. At this point, tapeId does NOT have
* a target/lun reserved.
*/
if(tapeId) {
[tapeId free];
}
return brtn;
}
- (stInitReturn_t) initSCSITape:(int)iunit /* IODevice unit # */
target: (u_char) stTarget
lun: (u_char) stLun
controller: controllerId
majorDeviceNumber: (int) major
{
inquiry_reply_t inquiryData;
sc_status_t rtn;
char driveType[DRIVE_TYPE_LENGTH]; /* name from Inquiry */
char *outp;
char deviceName[30];
char location[IO_STRING_LENGTH];
/*
* Initialize common instance variables.
*/
_controller = controllerId;
_target = stTarget;
_lun = stLun;
sprintf(deviceName, "st%d", iunit);
[self setName: deviceName];
[self setDeviceKind:"SCSITape"];
[self setLocation:[_controller name]];
[self setUnit: iunit];
#ifdef DEBUG
IOLog
("InitSCSITape: target %d lun %d unit %d deviceName %s location %s\n",
stTarget, stLun, iunit, deviceName, [_controller name]);
#endif DEBUG
/*
* Resources for commands during initialization.
*/
_senseDataPtr = IOMalloc (sizeof (struct esense_reply));
_senseDataValid = NO;
/*
* Other instance variables
*/
_didWrite = NO;
_suppressIllegalLength = NO;
_isInitialized = NO;
_devLock = nil; // Until we know we're a tape
/*
* Test Unit Ready to clear possible Unit Attention. Success is
* not important.
*/
[self stTestReady];
/*
* Try an Inquiry command.
*/
bzero(&inquiryData, sizeof(inquiry_reply_t));
rtn = [self stInquiry:&inquiryData];
#ifdef DEBUG
IOLog ("InitSCSITape inquiry returned %d\n", rtn);
#endif DEBUG
switch(rtn) {
case SR_IOST_GOOD:
break;
case SR_IOST_SELTO:
return STR_SELECTTO;
default:
return STR_ERROR;
}
/*
* Is it a tape?
*/
if(inquiryData.ir_qual != DEVQUAL_OK ||
inquiryData.ir_devicetype != DEVTYPE_TAPE) {
#ifdef DEBUG
IOLog ("InitSCSITape: not a tape\n");
#endif DEBUG
return(STR_NOTATAPE);
}
/*
* Set up resources for exclusive open.
*/
_devLock = [[NXLock alloc] init];
_devAcquired = NO;
/*
* Compress multiple blanks out of the vendor id and product ID.
*/
bzero (driveType, DRIVE_TYPE_LENGTH);
outp = driveType;
outp += moveString((char *)&inquiryData.ir_vendorid,
outp,
8,
&driveType[DRIVE_TYPE_LENGTH] - outp);
if(*(outp - 1) != ' ')
*outp++ = ' ';
outp += moveString((char *)&inquiryData.ir_productid,
outp,
16,
&driveType[DRIVE_TYPE_LENGTH] - outp);
if(*(outp - 1) != ' ')
*outp++ = ' ';
outp += moveString((char *)&inquiryData.ir_revision,
outp,
4,
&driveType[DRIVE_TYPE_LENGTH] - outp);
*outp = '\0';
sprintf(location, "Target %d LUN %d at %s", _target, _lun,
[controllerId name]);
[self setLocation: location];
IOLog("%s: %s\n", deviceName, driveType);
/*
* Do another Test Unit Ready to clear a possible Unit Attention
* condition. We don't care about the result.
*/
[self stTestReady];
/*
* Init to variable blk size.
*/
[self setBlockSize: 0];
/*
* Store the major number in our instance.
*/
_majorDevNum = major;
[super init];
_isInitialized = YES;
return(STR_GOOD);
} /* - initSCSITape: */
- free
{
if (_senseDataPtr)
IOFree (_senseDataPtr, sizeof (struct esense_reply));
if (_devLock)
[_devLock free];
if (_reservedTargetLun)
[_controller releaseTarget: _target lun: _lun forOwner: _controller];
return [super free];
}
- (IOReturn) getIntValues: (unsigned int *)values
forParameter: (IOParameterName) parameter
count: (unsigned int *) count
{
int maxCount = *count;
if(maxCount == 0) {
maxCount = IO_MAX_PARAMETER_ARRAY_LENGTH;
}
if(strcmp(parameter, "IOMajorDevice") == 0) {
values [0] = [self majorDevNum];
*count = 1;
return IO_R_SUCCESS;
}
if (strcmp(parameter, "Unit") == 0) {
values [0] = [self unit];
*count = 1;
return IO_R_SUCCESS;
}
return [super getIntValues:values
forParameter:parameter
count:&maxCount];
}
/*
* Gets and sets for instance variables.
*/
- (int) target /* Set only during initialization */
{
return (int) _target;
}
- (int) lun /* Set only during initialization */
{
return (int) _lun;
}
- controller /* Set only during initialization */
{
return _controller;
}
- (BOOL) isInitialized /* Object has been initialized */
{
return _isInitialized;
}
- (BOOL) didWrite /* Last command was a write */
{
return _didWrite;
}
- (BOOL) isFixedBlock
{
if (_blockSize) { /* Zero blocksize means variable block size */
return YES;
} else {
return NO;
}
}
- (BOOL) senseDataValid
{
return _senseDataValid;
}
- forceSenseDataInvalid /* for MTIOCGET and friends */
{
_senseDataValid = NO;
return self;
}
- (struct esense_reply *) senseDataPtr
{
return _senseDataPtr;
}
- (int) blockSize /* Set only via setBlockSize SCSI operation */
{
return _blockSize;
}
- (BOOL) suppressIllegalLength
{
return _suppressIllegalLength;
}
- setSuppressIllegalLength: (BOOL) condition
{
_suppressIllegalLength = condition;
return self;
}
- (BOOL) ignoreCheckCondition
{
return _ignoreCheckCondition;
}
- setIgnoreCheckCondition: (BOOL) condition
{
_ignoreCheckCondition = condition;
return self;
}
- (int) majorDevNum
{
return _majorDevNum;
}
- setReservedTargetLun: (BOOL) condition
{
_reservedTargetLun = condition;
return self;
}
- (BOOL) reservedTargetLun
{
return _reservedTargetLun;
}
- (IOReturn) acquireDevice
{
IOReturn ret = IO_R_INVALID;
[_devLock lock];
if (_devAcquired == YES) {
ret = IO_R_BUSY;
} else {
_devAcquired = YES;
ret = IO_R_SUCCESS;
}
[_devLock unlock];
return ret;
}
- (IOReturn) releaseDevice
{
[_devLock lock];
_devAcquired = NO;
[_devLock unlock];
return IO_R_SUCCESS;
}
/*
* General SCSI commands
*/
- (sc_status_t) stInquiry: (inquiry_reply_t *) inquiryReply
{
IOSCSIRequest scsiReq;
cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
inquiry_reply_t *alignedReply;
void *freePtr;
int freeCnt;
sc_status_t rtn;
IODMAAlignment dmaAlign;
/*
* Get some well-aligned memory.
*/
alignedReply = [_controller
allocateBufferOfLength: sizeof(inquiry_reply_t)
actualStart:&freePtr
actualLength:&freeCnt];
bzero(alignedReply, sizeof(inquiry_reply_t));
bzero(&scsiReq, sizeof(IOSCSIRequest));
scsiReq.target = _target;
scsiReq.lun = _lun;
scsiReq.read = YES;
/*
* Get appropriate alignment from controller.
*/
[_controller getDMAAlignment:&dmaAlign];
if(dmaAlign.readLength > 1) {
scsiReq.maxTransfer = IOAlign(int, sizeof(inquiry_reply_t),
dmaAlign.readLength);
}
else {
scsiReq.maxTransfer = sizeof(inquiry_reply_t);
}
scsiReq.timeoutLength = ST_IOTO_NORM;
scsiReq.disconnect = 1;
cdbp->c6_opcode = C6OP_INQUIRY;
cdbp->c6_lun = _lun;
cdbp->c6_len = sizeof(inquiry_reply_t);
[self executeRequest: &scsiReq
buffer: alignedReply
client: IOVmTaskSelf()
senseBuf: _senseDataPtr];
if(scsiReq.driverStatus == SR_IOST_GOOD) {
unsigned required = (char *)(&alignedReply->ir_zero3[0]) -
(char *)(alignedReply);
if(scsiReq.bytesTransferred < required) {
IOLog("%s: bad DMA Transfer count (%d) on Inquiry\n",
[self name], scsiReq.bytesTransferred);
rtn = SR_IOST_HW;
}
else {
/*
* Copy data back to caller's struct. Zero the
* portion of alignedReply which did not get valid
* data; the last flush out of the DMA pipe could
* have written trash to it (and our caller
* expects NULL data).
*/
unsigned zeroSize;
zeroSize = sizeof(*alignedReply) - scsiReq.bytesTransferred;
if(zeroSize) {
bzero((char *)alignedReply + scsiReq.bytesTransferred,
zeroSize);
}
*inquiryReply = *alignedReply;
rtn = scsiReq.driverStatus;
}
}
else {
rtn = scsiReq.driverStatus;
}
IOFree(freePtr, freeCnt);
return rtn;
} /* - stInquiry: */
- (BOOL) stTestReady
{
IOSCSIRequest scsiReq;
cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
BOOL rtn;
bzero(&scsiReq, sizeof(IOSCSIRequest));
scsiReq.target = _target;
scsiReq.lun = _lun;
scsiReq.timeoutLength = ST_IOTO_NORM;
scsiReq.disconnect = 1;
cdbp->c6_opcode = C6OP_TESTRDY;
cdbp->c6_lun = _lun;
[self executeRequest: &scsiReq
buffer: (void *) NULL
client: IOVmTaskSelf()
senseBuf: _senseDataPtr];
/*
* XXX Do we need to distinguish not ready from no tape?
*/
switch(scsiReq.driverStatus) {
case SR_IOST_GOOD:
rtn = YES;
break;
default:
rtn = NO;
break;
}
return rtn;
} /* - stTestReady: */
- (sc_status_t) stCloseFile
{
IOSCSIRequest scsiReq;
cdb_6s_t *cdbp = &scsiReq.cdb.cdb_c6s;
bzero(&scsiReq, sizeof(IOSCSIRequest));
scsiReq.target = _target;
scsiReq.lun = _lun;
scsiReq.timeoutLength = ST_IOTO_NORM;
scsiReq.disconnect = 1;
cdbp->c6s_opcode = C6OP_WRTFM;
assign_cdb_c6s_len (cdbp, 1); /* one file mark */
return [self executeRequest: &scsiReq
buffer: NULL
client: IOVmTaskSelf()
senseBuf: _senseDataPtr];
} /* - stCloseFile */
- (sc_status_t) stRewind
{
IOSCSIRequest scsiReq;
cdb_6s_t *cdbp = &scsiReq.cdb.cdb_c6s;
bzero(&scsiReq, sizeof(IOSCSIRequest));
scsiReq.target = _target;
scsiReq.lun = _lun;
scsiReq.timeoutLength = ST_IOTO_RWD;
scsiReq.disconnect = 1;
cdbp->c6s_opcode = C6OP_REWIND;
return [self executeRequest: &scsiReq
buffer: NULL
client: IOVmTaskSelf()
senseBuf: _senseDataPtr];
} /* - stRewind */
/*
* Get sense data. senseBuf does not have to be well aligned.
*/
- (sc_status_t) requestSense: (esense_reply_t *)senseBuf
{
IOSCSIRequest scsiReq;
cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
esense_reply_t *alignedBuf;
void *freePtr;
int freeCnt;
sc_status_t rtn;
IODMAAlignment dmaAlign;
alignedBuf = [_controller allocateBufferOfLength: sizeof(esense_reply_t)
actualStart: &freePtr
actualLength: &freeCnt];
bzero(&scsiReq, sizeof(IOSCSIRequest));
[_controller getDMAAlignment:&dmaAlign];
scsiReq.target = _target;
scsiReq.lun = _lun;
scsiReq.read = YES;
if(dmaAlign.readLength > 1) {
scsiReq.maxTransfer = IOAlign(int, sizeof(esense_reply_t),
dmaAlign.readLength);
} else {
scsiReq.maxTransfer = sizeof(esense_reply_t);
}
scsiReq.timeoutLength = ST_IOTO_NORM; // XXX Should be ST_IOTO_SENSE??
scsiReq.disconnect = 0;
cdbp->c6_opcode = C6OP_REQSENSE;
cdbp->c6_lun = _lun;
cdbp->c6_len = sizeof(esense_reply_t);
rtn = [_controller executeRequest:&scsiReq
buffer:alignedBuf
client:IOVmTaskSelf()];
if(rtn == SR_IOST_GOOD) {
*senseBuf = *alignedBuf;
_senseDataValid = YES;
}
IOFree(freePtr, freeCnt);
return rtn;
} /* - requestSense: */
- (sc_status_t) stModeSelect: (struct modesel_parms *) modeSelectParmsPtr
{
IOSCSIRequest scsiReq;
cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
int count = modeSelectParmsPtr->msp_bcount;
struct mode_sel_data *alignedBuf;
void *freePtr;
int freeCnt;
sc_status_t rtn;
IODMAAlignment dmaAlign;
alignedBuf = [_controller
allocateBufferOfLength: count
actualStart: &freePtr
actualLength: &freeCnt];
bzero(&scsiReq, sizeof(IOSCSIRequest));
scsiReq.target = _target;
scsiReq.lun = _lun;
scsiReq.read = NO;
[_controller getDMAAlignment:&dmaAlign];
if(dmaAlign.readLength > 1) {
scsiReq.maxTransfer = IOAlign(int, count,
dmaAlign.readLength);
} else {
scsiReq.maxTransfer = count;
}
scsiReq.timeoutLength = ST_IOTO_NORM;
scsiReq.disconnect = 1;
cdbp->c6_opcode = C6OP_MODESELECT;
cdbp->c6_lun = _lun;
cdbp->c6_len = count;
bcopy (&modeSelectParmsPtr->msp_data, alignedBuf, count);
rtn = [self executeRequest:&scsiReq
buffer:alignedBuf
client:IOVmTaskSelf()
senseBuf: _senseDataPtr];
IOFree(freePtr, freeCnt);
return rtn;
} /* - stModeSelect: */
- (sc_status_t) stModeSense: (struct modesel_parms *) modeSenseParmsPtr
{
IOSCSIRequest scsiReq;
cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
int count = modeSenseParmsPtr->msp_bcount;
struct mode_sel_data *alignedBuf;
void *freePtr;
int freeCnt;
sc_status_t rtn;
IODMAAlignment dmaAlign;
alignedBuf = [_controller
allocateBufferOfLength: count
actualStart: &freePtr
actualLength: &freeCnt];
bzero(&scsiReq, sizeof(IOSCSIRequest));
scsiReq.target = _target;
scsiReq.lun = _lun;
scsiReq.read = YES;
[_controller getDMAAlignment:&dmaAlign];
if(dmaAlign.readLength > 1) {
scsiReq.maxTransfer = IOAlign(int, count,
dmaAlign.readLength);
} else {
scsiReq.maxTransfer = count;
}
scsiReq.timeoutLength = ST_IOTO_NORM;
scsiReq.disconnect = 1;
cdbp->c6_opcode = C6OP_MODESENSE;
cdbp->c6_lun = _lun;
cdbp->c6_len = count;
rtn = [self executeRequest:&scsiReq
buffer:alignedBuf
client:IOVmTaskSelf()
senseBuf: _senseDataPtr];
if(rtn == SR_IOST_GOOD) {
bcopy (alignedBuf, &modeSenseParmsPtr->msp_data, count);
}
IOFree(freePtr, freeCnt);
return rtn;
} /* - stModeSense: */
- (sc_status_t) executeMTOperation: (struct mtop *) mtopp
{
IOSCSIRequest scsiReq;
cdb_6s_t *cdbp = &scsiReq.cdb.cdb_c6s;
int count;
sc_status_t rtn;
bzero(&scsiReq, sizeof(IOSCSIRequest));
scsiReq.target = _target;
scsiReq.lun = _lun;
scsiReq.timeoutLength = ST_IOTO_NORM; /* Some ops override this */
scsiReq.disconnect = 1; // XXX - maybe not for all ops.
/*
* none of these operations performs DMA. For each, just fill in
* the cdb, and pass it to the controller.
*/
/* build a CDB */
switch(mtopp->mt_op) {
case MTWEOF: /* write file marks */
cdbp->c6s_opcode = C6OP_WRTFM;
goto setcount_f;
case MTFSF: /* space file marks forward */
cdbp->c6s_opcode = C6OP_SPACE;
cdbp->c6s_opt = C6OPT_SPACE_FM;
scsiReq.timeoutLength = mtopp->mt_count * ST_IOTO_SPFM;
goto setcount_f;
case MTBSF: /* space file marks backward */
cdbp->c6s_opcode = C6OP_SPACE;
cdbp->c6s_opt = C6OPT_SPACE_FM;
scsiReq.timeoutLength = mtopp->mt_count * ST_IOTO_SPFM;
goto setcount_b;
case MTFSR: /* space records forward */
cdbp->c6s_opcode = C6OP_SPACE;
cdbp->c6s_opt = C6OPT_SPACE_LB;
scsiReq.timeoutLength = ST_IOTO_SPR;
setcount_f:
assign_cdb_c6s_len (cdbp, mtopp->mt_count);
break;
case MTBSR: /* space records backward */
cdbp->c6s_opcode = C6OP_SPACE;
cdbp->c6s_opt = C6OPT_SPACE_LB;
scsiReq.timeoutLength = ST_IOTO_SPR;
setcount_b:
count = 0 - mtopp->mt_count;
assign_cdb_c6s_len (cdbp, count);
break;
case MTREW: /* rewind */
cdbp->c6s_opcode = C6OP_REWIND;
scsiReq.timeoutLength = ST_IOTO_RWD;
break;
case MTOFFL: /* set offline */
cdbp->c6s_opcode = C6OP_STARTSTOP;
/* note load bit is 0 */
scsiReq.timeoutLength = ST_IOTO_RWD;
break;
case MTNOP: /* nop / get status */
case MTCACHE: /* enable cache */
case MTNOCACHE: /* disable cache */
case MTRETEN:
case MTERASE:
default:
rtn = SR_IOST_CMDREJ; /* FIXME: unsupported? */
goto out;
}
rtn = [self executeRequest: &scsiReq
buffer: NULL
client: IOVmTaskSelf()
senseBuf: _senseDataPtr];
out:
return rtn;
} /* - executeMTOperation: */
/*
* Set block size for SCSI tape device.
*
* blocksize == 0 --> variable
* blocksize != 0 --> fixed @ blocksize
*
* First, execute mode sense, then mode select with block length
* set to 0 (variable) or blocksize (fixed)
*/
- (IOReturn) setBlockSize: (int) blockSize
{
int rtn;
struct modesel_parms *mspp;
struct mode_sel_hdr *mshp;
mspp = IOMalloc (sizeof(struct modesel_parms));
mspp->msp_bcount = sizeof(struct mode_sel_hdr) +
sizeof(struct mode_sel_bd);
if((rtn = [self stModeSense: mspp]) != SR_IOST_GOOD) {
IOFree (mspp, sizeof (struct modesel_parms));
return [_controller returnFromScStatus: rtn];
}
mshp = &mspp->msp_data.msd_header;
mshp->msh_sd_length_0 = 0;
mshp-> msh_med_type = 0;
mshp-> msh_wp = 0;
mshp-> msh_bd_length = sizeof(struct mode_sel_bd);
assign_msbd_blocklength
(&mspp->msp_data.msd_blockdescript, blockSize);
assign_msbd_numblocks
(&mspp->msp_data.msd_blockdescript, 0);
if((rtn = [self stModeSelect: mspp]) != SR_IOST_GOOD) {
IOFree (mspp, sizeof (struct modesel_parms));
return [_controller returnFromScStatus: rtn];
}
_blockSize = blockSize;
IOFree (mspp, sizeof (struct modesel_parms));
return IO_R_SUCCESS;
} /* - setBlockSize: */
/*
* Execute CDB. Buffer must be well aligned. If command results
* in Check Status, return the sense data in *senseBuf.
*/
- (sc_status_t) executeRequest: (IOSCSIRequest *)scsiReq
buffer:(void *) buffer /* data destination */
client:(vm_task_t) client
senseBuf:(esense_reply_t *) senseBuf
{
sc_status_t rtn;
_senseDataValid = NO;
#ifdef DEBUG
IOLog("Entered SCSI Tape executeRequest: op %s, maxTransfer %d, len %d\n",
IOFindNameForValue(scsiReq->cdb.cdb_opcode,
IOSCSIOpcodeStrings),
scsiReq->maxTransfer,
(scsiReq->cdb.cdb_c6s.c6s_len2 << 16) |
(scsiReq->cdb.cdb_c6s.c6s_len1 << 8) |
(scsiReq->cdb.cdb_c6s.c6s_len0));
#endif DEBUG
rtn = [_controller executeRequest:scsiReq
buffer:buffer
client:client];
#ifdef DEBUG
IOLog ("Length %d on return from executeRequest\n", scsiReq->bytesTransferred);
#endif DEBUG
/*
* Log error returns.
*/
if (rtn != SR_IOST_GOOD) {
/*
* If result is Check Condition, do a Request Sense, unless suppressed.
*/
if(rtn == SR_IOST_CHKSV) {
/*
* Host Adaptor already got us sense data. Give sense data
* to user and save it.
*/
*senseBuf = *_senseDataPtr = scsiReq->senseData;
_senseDataValid = YES;
}
if (((rtn == SR_IOST_CHKSNV) || (rtn == SR_IOST_CHKSV)) &&
!_ignoreCheckCondition) {
if(rtn == SR_IOST_CHKSV) {
rtn = SR_IOST_GOOD;
}
else {
rtn = [self requestSense: senseBuf];
}
if(rtn == SR_IOST_GOOD) {
/*
* If the error is a filemark, and we are reading,
* then return no error. Otherwise, return
* check sense, with valid sense data.
*/
if ((scsiReq->cdb.cdb_c6.c6_opcode == C6OP_READ) &&
(senseBuf->er_filemark)) {
/*
* Check for correct reporting of bytes transferred.
* (This works around a DPT firmware bug.)
*/
int transferLength =
cdb_c6s_len_value (&scsiReq->cdb.cdb_c6s) -
er_info_value (senseBuf);
if ([self isFixedBlock]) {
transferLength = transferLength * _blockSize;
}
if (scsiReq->bytesTransferred != transferLength) {
#ifdef DEBUG
IOLog ("%s: Incorrect byte count reported - "
"corrected to %d\n", [self name], transferLength);
#endif DEBUG
scsiReq->bytesTransferred = transferLength;
}
rtn = SR_IOST_GOOD;
scsiReq->driverStatus = SR_IOST_GOOD;
#ifdef DEBUG
IOLog ("execReq sense: er_filemark %d, er_badlen %d, er_sensekey %d, er_addsensecode %d, er_qualifier %d, er_info %d\n",
senseBuf->er_filemark, senseBuf->er_badlen, senseBuf->er_sensekey,
senseBuf->er_addsensecode, senseBuf->er_qualifier,
er_info_value (senseBuf));
#endif DEBUG
}
else {
rtn = SR_IOST_CHKSV;
}
}
else {
if (_isInitialized) {
IOLog("%s: Request Sense on target %d lun %d "
"failed (%s)\n",
[self name], _target, _lun,
IOFindNameForValue(rtn, IOScStatusStrings));
}
rtn = SR_IOST_CHKSNV;
}
}
/*
* Log error messages, except the spate of timeouts and
* device not ready messages during initialization.
*/
if (_isInitialized &&
(rtn != SR_IOST_GOOD) &&
!_ignoreCheckCondition) {
IOLog("%s, target %d, lun %d: op %s returned %s\n",
[self name], _target, _lun,
IOFindNameForValue(scsiReq->cdb.cdb_opcode,
IOSCSIOpcodeStrings),
IOFindNameForValue(rtn, IOScStatusStrings));
if (rtn == SR_IOST_CHKSV) {
IOLog (" Sense key = 0x%x Sense Code = 0x%x\n",
senseBuf->er_sensekey, senseBuf->er_addsensecode);
}
}
_didWrite = NO;
}
else {
/* Remember good writes for device close */
if (scsiReq->cdb.cdb_opcode == C6OP_WRITE) {
_didWrite = YES;
} else {
_didWrite = NO;
}
}
return rtn;
} /* executeRequest: */
@end
/*
* Supporting functions.
*/
/*
* moveString is taken directly from SCSIDiskPrivate.m.
* It's used by -initSCSITape:
*
* Copy inp to outp for up to inlength input characters or outlength output
* characters. Compress multiple spaces and eliminate nulls. Returns number
* of characters copied to outp.
*/
static int
moveString(char *inp, char *outp, int inlength, int outlength)
{
int lastCharSpace = 0;
char *outpStart = outp;
while(inlength && outlength) {
switch(*inp) {
case '\0':
inp++;
inlength--;
continue;
case ' ':
if(lastCharSpace) {
inp++;
inlength--;
continue;
}
lastCharSpace = 1;
goto copyit;
default:
lastCharSpace = 0;
copyit:
*outp++ = *inp++;
inlength--;
outlength--;
break;
}
}
return(outp - outpStart);
}
void
assign_cdb_c6s_len (struct cdb_6s *cdbp, int length)
{
#if __BIG_ENDIAN__
#if __NATURAL_ALIGNMENT__
cdbp->c6s_len[0] = (length >> 16) & 0xff;
cdbp->c6s_len[1] = (length >> 8) & 0xff;
cdbp->c6s_len[2] = length & 0xff;
#else __NATURAL_ALIGNMENT__
cdbp->c6s_len = length;
#endif __NATURAL_ALIGNMENT__
#elif __LITTLE_ENDIAN__
cdbp->c6s_len0 = (u_char) length & 0xff;
cdbp->c6s_len1 = (u_char) (length >> 8) & 0xff;
cdbp->c6s_len2 = (u_char) (length >> 16) & 0xff;
#endif
return;
}
void
assign_msbd_numblocks (struct mode_sel_bd *msbdp, int numblocks)
{
#if __BIG_ENDIAN__
msbdp->msbd_numblocks = numblocks;
#elif __LITTLE_ENDIAN__
msbdp->msbd_numblocks0 = (u_char) numblocks & 0xff;
msbdp->msbd_numblocks1 = (u_char) (numblocks >> 8) & 0xff;
msbdp->msbd_numblocks2 = (u_char) (numblocks >> 16) & 0xff;
#endif
return;
}
void
assign_msbd_blocklength (struct mode_sel_bd *msbdp, int length)
{
#if __BIG_ENDIAN__
msbdp->msbd_blocklength = length;
#elif __LITTLE_ENDIAN__
msbdp->msbd_blocklength0 = (u_char) length & 0xff;
msbdp->msbd_blocklength1 = (u_char) (length >> 8) & 0xff;
msbdp->msbd_blocklength2 = (u_char) (length >> 16) & 0xff;
#endif
return;
}
int
cdb_c6s_len_value (struct cdb_6s *cdbp)
{
#if __BIG_ENDIAN__
return (cdbp->c6s_len);
#elif __LITTLE_ENDIAN__
return (cdbp->c6s_len0 | (cdbp->c6s_len1 << 8) | (cdbp->c6s_len2 << 16));
#endif
}
int
er_info_value (struct esense_reply *esrp)
{
#if __BIG_ENDIAN__
return (esrp->er_info);
#elif __LITTLE_ENDIAN__
return (esrp->er_info0 | (esrp->er_info1 << 8) |
(esrp->er_info2 << 16) | (esrp->er_info3 << 24));
#endif
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.