IOFireWireIPCommand.cpp [plain text]
#define FIREWIREPRIVATE
#include <IOKit/firewire/IOFireWireController.h>
#include <IOKit/firewire/IOFireWireNub.h>
#include <IOKit/IOSyncer.h>
#include "IOFireWireIPCommand.h"
#include "IOFWIPBusInterface.h"
#define BCOPY(s, d, l) do { bcopy((void *) s, (void *) d, l); } while(0)
#pragma mark -
#pragma mark еее IOFWIPAsyncWriteCommand methods еее
OSDefineMetaClassAndStructors(IOFWIPAsyncWriteCommand, IOFWWriteCommand);
OSMetaClassDefineReservedUnused(IOFWIPAsyncWriteCommand, 0);
OSMetaClassDefineReservedUnused(IOFWIPAsyncWriteCommand, 1);
OSMetaClassDefineReservedUnused(IOFWIPAsyncWriteCommand, 2);
OSMetaClassDefineReservedUnused(IOFWIPAsyncWriteCommand, 3);
bool IOFWIPAsyncWriteCommand::initAll(IOFireWireIP *networkObject, IOFWIPBusInterface *fwIPBusIfObject, UInt32 cmdLen, FWAddress devAddress, FWDeviceCallback completion, void *refcon, bool failOnReset)
{
fIPLocalNode = networkObject;
if(!fIPLocalNode)
return false;
IOFireWireNub *device = fIPLocalNode->getDevice();
if(!IOFWWriteCommand::initWithController(device->getController()))
return false;
fBuffer = new IOBufferMemoryDescriptor;
if(fBuffer == NULL)
return false;
if(!fBuffer->initWithOptions(kIODirectionOut | kIOMemoryUnshared, cmdLen, 1))
return false;
fMem = IOMemoryDescriptor::withAddress((void *)fBuffer->getBytesNoCopy(), cmdLen,
kIODirectionOut);
if(!fMem)
return false;
fCursorBuf = (UInt8*)getBufferFromDescriptor();
maxBufLen = cmdLen;
fMaxRetries = 2;
fCurRetries = fMaxRetries;
fMemDesc = fMem;
fComplete = completion;
fSync = completion == NULL;
fRefCon = refcon;
fTimeout = 1000*125;
if(fMem)
fSize = fMem->getLength();
fBytesTransferred = 0;
fLinkFragmentType = UNFRAGMENTED;
fDevice = device;
device->getNodeIDGeneration(fGeneration, fNodeID);
fAddressHi = devAddress.addressHi;
fAddressLo = devAddress.addressLo;
fMaxPack = 1 << device->maxPackLog(fWrite, devAddress);
fSpeed = fControl->FWSpeed(fNodeID);
fFailOnReset = failOnReset;
if(fwIPBusIfObject)
{
fIPBusIf = fwIPBusIfObject;
fIPBusIf->retain();
}
return true;
}
void IOFWIPAsyncWriteCommand::free()
{
if(fIPBusIf)
{
fIPBusIf->release();
fIPBusIf = NULL;
}
if(fBuffer){
fBuffer->release();
fBuffer = NULL;
}
if(fMem){
fMem->release();
fMem = NULL;
}
IOFWWriteCommand::free();
}
void IOFWIPAsyncWriteCommand::wait()
{
IODelay(fTimeout);
}
IOReturn IOFWIPAsyncWriteCommand::reinit(IOFireWireNub *device, UInt32 cmdLen,
FWAddress devAddress, FWDeviceCallback completion, void *refcon,
bool failOnReset, bool deferNotify)
{
if(cmdLen > maxBufLen)
return kIOFireWireIPNoResources;
fComplete = completion;
fRefCon = refcon;
if(fMem)
fSize = cmdLen;
fBytesTransferred = 0;
fDevice = device;
device->getNodeIDGeneration(fGeneration, fNodeID);
fAddressHi = devAddress.addressHi;
fAddressLo = devAddress.addressLo;
fMaxPack = 1 << device->maxPackLog(fWrite, devAddress);
fSpeed = fControl->FWSpeed(fNodeID);
fFailOnReset = failOnReset;
fMaxRetries = 2;
fCurRetries = fMaxRetries;
fTimeout = 1000*125;
setDeferredNotify(deferNotify);
IOFWWriteCommand::setFastRetryOnBusy(fIPLocalNode->fIPoFWDiagnostics.fDoFastRetry);
return kIOReturnSuccess;
}
IOReturn IOFWIPAsyncWriteCommand::transmit(IOFireWireNub *device, UInt32 cmdLen,
FWAddress devAddress, FWDeviceCallback completion, void *refcon,
bool failOnReset, bool deferNotify, bool doQueue, FragmentType fragmentType)
{
fLinkFragmentType = fragmentType;
return transmit(device, cmdLen, devAddress, completion, refcon, failOnReset, deferNotify, doQueue);
}
IOReturn IOFWIPAsyncWriteCommand::transmit(IOFireWireNub *device, UInt32 cmdLen,
FWAddress devAddress, FWDeviceCallback completion, void *refcon,
bool failOnReset, bool deferNotify, bool doQueue)
{
fMBufCommand->retain();
IOReturn status = initDescriptor(cmdLen);
if(status == kIOReturnSuccess)
status = reinit(device, cmdLen+fHeaderSize, devAddress, completion, refcon, failOnReset, deferNotify);
if(status == kIOReturnSuccess)
{
reInitCount = 0;
resetCount = 0;
reInitCount++;
submit(doQueue);
status = getStatus();
}
switch (status)
{
case kIOFireWireOutOfTLabels:
fIPLocalNode->fIPoFWDiagnostics.fSubmitErrs++;
break;
case kIOFireWireIPNoResources:
resetDescriptor(status);
((IOFWIPBusInterface*)refcon)->returnAsyncCommand(this);
fIPLocalNode->fIPoFWDiagnostics.fNoResources++;
status = kIOReturnSuccess;
break;
default: status = kIOReturnSuccess;
break;
}
return status;
}
IOReturn IOFWIPAsyncWriteCommand::createFragmentedDescriptors()
{
mbuf_t m = fMBufCommand->getMBuf();
mbuf_t srcm = m;
SInt32 srcLen = mbuf_len(srcm);
vm_address_t src = (vm_offset_t)mbuf_data(srcm);
SInt32 tempOffset = fOffset;
((IOFWIPBusInterface*)fRefCon)->moveMbufWithOffset(tempOffset, &srcm, &src, &srcLen);
SInt32 dstLen = fLength;
SInt32 copylen = dstLen;
mbuf_t temp = NULL;
for (;;)
{
if (fIndex > (MAX_ALLOWED_SEGS-3))
{
fTailMbuf = NULL;
fCursorBuf = fCursorBuf + fHeaderSize;
fLength = copylen;
UInt32 residual = copyToBufferDescriptors();
if(residual != 0)
return kIOFireWireIPNoResources;
fVirtualRange[fIndex].address = (IOVirtualAddress)(fCursorBuf);
fVirtualRange[fIndex].length = fLength;
fIndex++;
return kIOReturnSuccess;
}
if (srcLen < dstLen)
{
fVirtualRange[fIndex].address = (IOVirtualAddress)(src);
fVirtualRange[fIndex].length = srcLen;
fIndex++;
dstLen -= srcLen;
copylen -= srcLen;
fOffset = fOffset + srcLen;
if(copylen == 0)
{
temp = mbuf_next(srcm);
srcm = temp;
break;
}
temp = mbuf_next(srcm); assert(temp);
srcm = temp;
srcLen = mbuf_len(srcm);
src = (vm_offset_t)mbuf_data(srcm);
}
else if (srcLen > dstLen)
{
fVirtualRange[fIndex].address = (IOVirtualAddress)(src);
fVirtualRange[fIndex].length = dstLen;
fIndex++;
src += dstLen;
srcLen -= dstLen;
copylen -= dstLen;
fOffset = fOffset + dstLen;
if(copylen == 0)
break; }
else
{
fVirtualRange[fIndex].address = (IOVirtualAddress)(src);
fVirtualRange[fIndex].length = srcLen;
fIndex++;
copylen -= srcLen;
if(copylen == 0)
{
fOffset = 0;
temp = mbuf_next(srcm);
srcm = temp;
break;
}
srcm = mbuf_next(srcm);
if (dstLen == 0)
break;
srcLen = mbuf_len(srcm);
src = (vm_offset_t)mbuf_data(srcm);
}
}
return copylen;
}
IOReturn IOFWIPAsyncWriteCommand::createUnFragmentedDescriptors()
{
mbuf_t m = fMBufCommand->getMBuf();
mbuf_t n = 0;
UInt32 totalLength = 0;
UInt32 residual = 0;
UInt32 pktLen = 0;
UInt32 offset = 0;
fIndex = 0;
if (mbuf_flags(m) & M_PKTHDR)
{
pktLen = mbuf_pkthdr_len(m);
offset = fOffset;
}
while (m)
{
if(mbuf_data(m) != NULL)
{
fVirtualRange[fIndex].address = (IOVirtualAddress)((UInt8*)mbuf_data(m) + offset);
fVirtualRange[fIndex].length = mbuf_len(m) - offset;
totalLength += fVirtualRange[fIndex].length;
fIndex++;
}
offset = 0;
m = mbuf_next(m);
if ((fIndex > MAX_ALLOWED_SEGS-3) && (m != NULL))
{
n = mbuf_next(m);
if(n == NULL)
{
fVirtualRange[fIndex].address = (IOVirtualAddress)(mbuf_data(m));
fVirtualRange[fIndex].length = mbuf_len(m);
}
else
{
fTailMbuf = m;
fLength = fLength - totalLength + fHeaderSize;
fCursorBuf = (UInt8*)getBufferFromDescriptor();
residual = copyToBufferDescriptors();
if(residual != 0)
return kIOFireWireIPNoResources;
fVirtualRange[fIndex].address = (IOVirtualAddress)(fCursorBuf);
fVirtualRange[fIndex].length = fLength;
}
fIndex++;
return kIOReturnSuccess;
}
}
return kIOReturnSuccess;
}
IOReturn IOFWIPAsyncWriteCommand::copyToBufferDescriptors()
{
mbuf_t srcm = fMBufCommand->getMBuf();
SInt32 srcLen = mbuf_len(srcm);
vm_address_t src = (vm_offset_t)mbuf_data(srcm);
SInt32 tempOffset = 0;
if(fTailMbuf != NULL)
{
srcm = fTailMbuf;
srcLen = mbuf_len(srcm);
src = (vm_offset_t)mbuf_data(srcm);
}
else
{
tempOffset = fOffset;
((IOFWIPBusInterface*)fRefCon)->moveMbufWithOffset(tempOffset, &srcm, &src, &srcLen);
}
SInt32 dstLen = fLength;
SInt32 copylen = dstLen;
vm_address_t dst = (vm_address_t)fCursorBuf;
mbuf_t temp = NULL;
UInt32 totalLen = 0;
for (;;)
{
if (srcLen < dstLen)
{
BCOPY(src, dst, srcLen);
totalLen += srcLen;
dst += srcLen;
dstLen -= srcLen;
copylen -= srcLen;
fOffset = fOffset + srcLen;
if(copylen == 0)
{
temp = mbuf_next(srcm);
srcm = temp;
break;
}
temp = mbuf_next(srcm);
if(temp == NULL)
break;
assert(temp);
srcm = temp;
srcLen = mbuf_len(srcm);
src = (vm_offset_t)mbuf_data(srcm);
}
else if (srcLen > dstLen)
{
BCOPY(src, dst, dstLen);
totalLen += dstLen;
src += dstLen;
srcLen -= dstLen;
copylen -= dstLen;
fOffset = fOffset + dstLen;
if(copylen == 0)
break;
}
else
{
BCOPY(src, dst, srcLen);
totalLen += srcLen;
copylen -= srcLen;
if(copylen == 0)
{
fOffset = 0;
temp = mbuf_next(srcm);
srcm = temp;
break;
}
srcm = mbuf_next(srcm);
if (dstLen == 0)
break;
srcLen = mbuf_len(srcm);
src = (vm_offset_t)mbuf_data(srcm);
}
}
return copylen;
}
IOReturn IOFWIPAsyncWriteCommand::initDescriptor(UInt32 length)
{
fLength = length;
if(fCopy == true)
{
fVirtualRange[fIndex].address = (IOVirtualAddress)fCursorBuf;
fVirtualRange[fIndex].length = fLength + fHeaderSize;
fIndex++;
fCursorBuf = fCursorBuf + fHeaderSize;
if(copyToBufferDescriptors() != 0)
return kIOFireWireIPNoResources;
}
else
{
if(((fLinkFragmentType == UNFRAGMENTED) ? createUnFragmentedDescriptors() : createFragmentedDescriptors()) != kIOReturnSuccess)
return kIOFireWireIPNoResources;
}
bool ret = fMem->initWithRanges (fVirtualRange,
fIndex,
kIODirectionOut,
kernel_task,
true);
if(ret == false)
return kIOFireWireIPNoResources;
return kIOReturnSuccess;
}
void IOFWIPAsyncWriteCommand::resetDescriptor(IOReturn status)
{
memset(fVirtualRange, 0, sizeof(IOVirtualRange)*MAX_ALLOWED_SEGS);
fTailMbuf = NULL;
fCursorBuf = (UInt8*)getBufferFromDescriptor();
if( status == kIOReturnSuccess || status == kIOReturnBusy)
fIPLocalNode->fIPoFWDiagnostics.fFastRetryBusyAcks += getFastRetryCount();
fMBufCommand->releaseWithStatus(status);
fLinkFragmentType = UNFRAGMENTED;
fDevice = NULL;
fMBufCommand = NULL;
resetCount++;
}
void* IOFWIPAsyncWriteCommand::initPacketHeader(IOFWIPMBufCommand *mBufCommand, bool doCopy, FragmentType unfragmented, UInt32 headerSize, UInt32 offset)
{
fMBufCommand = mBufCommand;
fCopy = doCopy;
fOffset = offset;
fHeaderSize = headerSize;
fLinkFragmentType = unfragmented;
fIndex = 0;
if(fCopy == false)
{
if(unfragmented == UNFRAGMENTED)
{
fOffset = fOffset - fHeaderSize;
return (void*)((UInt8*)mbuf_data(fMBufCommand->getMBuf()) + fOffset);
}
else
{
fVirtualRange[fIndex].address = (IOVirtualAddress)(getCursorBuf());
fVirtualRange[fIndex].length = fHeaderSize;
fIndex++;
return getCursorBuf();
}
}
return getBufferFromDescriptor();
}
void IOFWIPAsyncWriteCommand::gotAck(int ackCode)
{
if ( (ackCode == kFWAckBusyX) || (ackCode == kFWAckBusyA) || (ackCode == kFWAckBusyB) )
fIPLocalNode->fIPoFWDiagnostics.fBusyAcks++;
IOFWWriteCommand::gotAck(ackCode);
}
void* IOFWIPAsyncWriteCommand::getCursorBuf()
{
return fCursorBuf;
}
void* IOFWIPAsyncWriteCommand::getBufferFromDescriptor()
{
return fBuffer->getBytesNoCopy();
}
UInt32 IOFWIPAsyncWriteCommand::getMaxBufLen()
{
return maxBufLen;
}
bool IOFWIPAsyncWriteCommand::notDoubleComplete()
{
return (reInitCount == resetCount);
}
#pragma mark -
#pragma mark еее IOFWIPAsyncStreamTxCommand methods еее
OSDefineMetaClassAndStructors(IOFWIPAsyncStreamTxCommand, IOFWAsyncStreamCommand);
OSMetaClassDefineReservedUnused(IOFWIPAsyncStreamTxCommand, 0);
OSMetaClassDefineReservedUnused(IOFWIPAsyncStreamTxCommand, 1);
OSMetaClassDefineReservedUnused(IOFWIPAsyncStreamTxCommand, 2);
OSMetaClassDefineReservedUnused(IOFWIPAsyncStreamTxCommand, 3);
bool IOFWIPAsyncStreamTxCommand::initAll(
IOFireWireIP *networkObject,
IOFireWireController *control,
IOFWIPBusInterface *fwIPBusIfObject,
UInt32 generation,
UInt32 channel,
UInt32 sync,
UInt32 tag,
UInt32 cmdLen,
int speed,
FWAsyncStreamCallback completion,
void *refcon)
{
if(!IOFWAsyncStreamCommand::initWithController(control))
return false;
fIPLocalNode = networkObject;
if(!fIPLocalNode)
return false;
fBuffer = new IOBufferMemoryDescriptor;
if(fBuffer == NULL)
return false;
if(!fBuffer->initWithOptions(kIODirectionOut | kIOMemoryUnshared, cmdLen, 1))
return false;
fMem = IOMemoryDescriptor::withAddress((void *)fBuffer->getBytesNoCopy(), cmdLen,
kIODirectionOut);
if(!fMem) {
return false;
}
maxBufLen = cmdLen;
fMaxRetries = 0;
fCurRetries = fMaxRetries;
fMemDesc = fMem;
fComplete = completion;
fSync = completion == NULL;
fRefCon = refcon;
fTimeout = 1000*125;
if(fMem)
fSize = fMem->getLength();
fGeneration = generation;
fChannel = channel;
fSyncBits = sync;
fTag = tag;
fSpeed = speed;
fFailOnReset = true;
if(fwIPBusIfObject)
{
fIPBusIf = fwIPBusIfObject;
fIPBusIf->retain();
}
return true;
}
void IOFWIPAsyncStreamTxCommand::wait()
{
IODelay(fTimeout);
}
void IOFWIPAsyncStreamTxCommand::free()
{
if(fIPBusIf)
{
fIPBusIf->release();
fIPBusIf = NULL;
}
if(fBuffer){
fBuffer->release();
fBuffer = NULL;
}
if(fMem){
fMem->release();
fMem = NULL;
}
IOFWAsyncStreamCommand::free();
}
IOReturn IOFWIPAsyncStreamTxCommand::reinit(
UInt32 generation,
UInt32 channel,
UInt32 cmdLen,
int speed,
FWAsyncStreamCallback completion,
void *refcon)
{
if(fStatus == kIOReturnBusy || fStatus == kIOFireWirePending)
return fStatus;
if(cmdLen > maxBufLen)
return kIOReturnNoResources;
fComplete = completion;
fRefCon = refcon;
if(fMem)
fSize = cmdLen;
fMaxRetries = 0;
fCurRetries = fMaxRetries;
fGeneration = generation;
fChannel = channel;
fSpeed = speed;
fTimeout = 1000*125;
return fStatus = kIOReturnSuccess;
}
void* IOFWIPAsyncStreamTxCommand::getBufferFromDesc()
{
return fBuffer->getBytesNoCopy();
}
UInt32 IOFWIPAsyncStreamTxCommand::getMaxBufLen()
{
return maxBufLen;
}