Garry,
In the theory it is easy… as long as you have your own HBA driver. Apple’s HBA drivers do not allow pass-through commands for a probably valid reason.
There are two ways doing what you would like to:
- userclient API-s of IOKitLib (well-documented, used the most)
- using setProperties() call and dispatching it.
Typically something like that:
IOReturn MyAHCICtrllr::setProperties(OSObject *properties)
{
OSDictionary *dict;
OSNumber *number;
UInt64 value;
UInt32 CommandCode;
UInt32 CommandArgument;
dict = OSDynamicCast(OSDictionary, properties);
if (!dict)
{
IOLog(“MyAHCICtrllr::setProperties() - kIOReturnBadArgument\n”);
return (kIOReturnBadArgument);
}
number = OSDynamicCast(OSNumber, dict->getObject(“FT-COMMAND”));
if (number)
{
value = number->unsigned64BitValue();
CommandCode = (value>>32);
CommandArgument = (UInt32)(value);
IOLog((“MyAHCICtrllr::setProperties() - called with %08lX code, %08lX argument\n”, (long unsigned int)CommandCode, (long unsigned int)CommandArgument);
return (Perform_Userspace_Command(CommandCode, CommandArgument));
}
return (super::setProperties(properties));
}
Take note of the
IOReturn MyAHCICtrllr::Perform_Userspace_Command(UInt32 CommandCode, UInt32 CommandArgument)
function - that is the dispatch function of the entire user-land call.
Typically - to make sure you are on the proper side of the “gate” - unlikely anyone going to “compete” with you but better to be on the safe side:
IOReturn MyAHCICtrllr::Perform_Userspace_Command(UInt32 CommandCode, UInt32 CommandArgument)
{
IOReturn result = this->m_CmdGate->runAction((IOCommandGate::Action)
&MyAHCICtrllr::Perform_Userspace_CommandActionWrapper,
(void *) CommandCode,
(void *) CommandArgument,
(void *) 0,
(void *) 0);
return (result);
}
IOReturn MyAHCICtrllr::Perform_Userspace_CommandActionWrapper(OSObject *owner,
void *arg0,
void *arg1,
void *arg2,
void *arg3)
{
MyAHCICtrllr *me = OSDynamicCast(FTSATACtrllr, (FTSATACtrllr *)owner);
UInt64 CommandCode64 = (UInt64)arg0;
UInt64 CommandArgument64 = (UInt64)arg1;
UInt32 CommandCode = (UInt32)CommandCode64;
UInt32 CommandArgument = (UInt32)CommandArgument64;
if (me != NULL);
{
return (me->GatedPerform_Userspace_Command(CommandCode, CommandArgument));
}
}
After all that the MyAHCICtrllr::GatedPerform_Userspace_Command does something like that:
IOReturn MyAHCICtrllr::GatedPerform_Userspace_Command(UInt32 CommandCode, UInt32 CommandArgument)
{
switch (CommandCode)
{
case xxxxx1:
{
break;
}
case xxxxx2:
{
break;
}
…
…
…
default:
{
IOLog(false, “MyAHCICtrllr::GatedPerform_Userspace_Command(): unknown command 0x%08lX\n”, (unsigned long int)CommandCode);
return (kIOReturnBadArgument);
}
}
return (kIOReturnSuccess);
}
And every case statement is doing something you want to do from the “user-land”.
A call from the user-land looks something like that:
kern_return_t SendMyCommandToController(io_registry_entry_t regEntry, UInt32 CommandCode, UInt32 argument)
{
CFMutableDictionaryRef dictRef;
CFNumberRef numberRef;
kern_return_t kernResult;
UInt64 number = 0ULL;
number = CommandCode;
number = (number << 32);
number = number | argument;
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &number);
dictRef = CFDictionaryCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks
);
CFDictionarySetValue(dictRef, __CFStringMakeConstantString(“My-Super-Duper-IO-Command”), numberRef);
kernResult = IORegistryEntrySetCFProperties(regEntry, dictRef);
CFRelease(numberRef);
CFRelease(dictRef);
return (kernResult);
}
So you are basically setting the entry “My-Super-Duper-IO-Command” to the value of “numberRef” within the registry associated with the driver controlling the HBA and your driver code is “catching” that and dispatching according own logic - other calls will be just transparent.
Now in order to do all that you have to have:
a) a utility which does the trick (lesser issue)
b) your own AHCI (or SAS) driver (a bigger issue).
Hope it helps… In any case, as you seeing from my other post I am in a “reverse” situation: I do have my AHCI driver under IOKit… and I am struggling now with the same for Win 7 / Win 8. Both of us having fun 