Copyright ©1995 by NeXT Computer, Inc.  All Rights Reserved.

IOSCSIControllerExported



Adopted By: IOSCSIController class
Declared In: driverkit/scsiTypes.h



Protocol Description

Indirect device drivers for devices attached to SCSI controllers use the methods in this protocol to communicate with IOSCSIController.



Method Types

Allocating well-aligned buffers allocateBufferOfLength:actualStart:actualLength:
getDMAAlignment:
Requesting I/O executeRequest:buffer:client:
maxTransfer
Reserving SCSI targets reserveTarget:lun:forOwner:
releaseTarget:lun:forOwner:
Resetting the SCSI bus resetSCSIBus
Getting the IOReturn equivalent of a sc_status_t value
returnFromScStatus:



Instance Methods

allocateBufferOfLength:actualStart:actualLength:
(void *)allocateBufferOfLength:(unsigned)length
actualStart:(void **)actualStart
actualLength:(unsigned *)actualLength

Allocates and returns a pointer to some well-aligned memory. Well-aligned memory is necessary for calls to executeRequest:buffer:client:. You should use actualStart and actualLength when freeing the memory, as follows (italicized text delineated in angle brackets, that is << >>, is to be filled in with device-specific code):

dataBuffer = [_controller allocateBufferOfLength:block_size
actualStart:&freePtr, actualLength:&freeLength];
<< Use the buffer... >>
IOFree(freePtr, freeLength);

Here's a typical use of this method:

IODMAAlignment    dmaAlign;
unsigned int      alignment, alignedLength, freeLength;
void             *alignedPtr = NULL;
unsigned int      maxLength; /* Max length of the current transfer */
/* . . . */
[_controller getDMAAlignment:&dmaAlign];
if(<< we're doing a write >>)
alignment = dmaAlign.writeLength;
else
alignment = dmaAlign.readLength;

if(alignment > 1)
alignedLength = IOAlign(unsigned int, maxLength, alignment);
else
alignedLength = maxLength;

alignedPtr = [_controller allocateBufferOfLength:alignedLength
actualStart:&freePtr
actualLength:&freeLength];

<< If we're going to do a write, copy the data to alignedPtr.
Set up the request and submit it, as described in the
executeRequest:buffer:client: description. >>
<< Do any post-I/O processing that's necessary. >>

IOFree(freePtr, freeLength);

See also:  getDMAAlignment:



executeRequest:buffer:client:
(sc_status_t)executeRequest:(IOSCSIRequest *)scsiRequest
buffer:(void *)buffer
client:(vm_task_t)client

Executes the specified request. Indirect devices invoke this method whenever they need the IOSCSIController to perform I/O.

Subclasses of IOSCSIController must implement this method. A typical implementation of this method consists of the following:

Using IOScheduleFunc() to schedule a timeout function to be called after scsiRequest->timeoutLength time has elapsed without I/O completion
Sending the command descriptor block (CDB) specified in scsiRequest to the controller
When the I/O has completed, unscheduling the timeout function

This method should return scsiRequest->driverStatus, which should be set by the part of the driver that detected I/O completion or timeout.

Indirect devices use this method as shown below (italicized text delineated in angle brackets, that is << >>, is to be filled in with device-specific code):

void             *alignedPtr = NULL;
unsigned int      alignedLength;
IOSCSIRequest     request;
cdb_t             cdb;

/* . . . */
if (<< we're going to be doing DMA >>) {
<< Ensure we have a well-aligned buffer that starts at alignedPtr
and continues for alignedLength bytes.  See the
allocateBuffer: description for one way of doing this. >>
} else {
alignedLength = 0;
alignedPtr = 0;
}

bzero(&request, sizeof(request));
request.target = [self target];
request.lun    = [self lun];
request.read = << YES if this is a read; NO otherwise >>;
request.maxTransfer = alignedLength;
request.timeoutLength = << some timeout length, in seconds >>;
request.disconnect = << 1 if allowed to disconnect; otherwise 0 >>;
request.cdb = cdb;
<< Set up the cdb (command descriptor block) field. The type of this
field, cdb_t, is defined and described in the header file
bsd/dev/scsireg.h. >>

rtn = [_controller executeRequest:&request
buffer:alignedPtr
client:IOVmTaskSelf()];


getDMAAlignment:
(void)getDMAAlignment:(IODMAAlignment *)alignment

Returns the DMA alignment requirements for the current architecture. IOSCSIController subclasses can override this method to specify any device-specific alignment requirements. See the description of allocateBufferOfLength:actualStart:actualLength: for an example of using this method.

See also:  allocateBufferOfLength:actualStart:actualLength:



maxTransfer
(unsigned)maxTransfer

Returns the maximum number of bytes per DMA transfer. This is the maximum transfer that can be requested in a call to executeRequest:buffer:client:.



releaseTarget:lun:forOwner:
(void)releaseTarget:(unsigned char)target
lun:(unsigned char)lun
forOwner:owner

Releases the specified target/lun pair. If owner hasn't reserved the pair, this method uses IOLog to print an error message.

See also:  reserveTarget:lun:forOwner:



reserveTarget:lun:forOwner:
(int)reserveTarget:(unsigned char)target
lun:(unsigned char)lun
forOwner:owner

Reserves the specified target/lun pair, if it isn't already reserved. This method is invoked by a client (for example, a SCSIDisk instance) to mark a particular target/lun as being in use by that client. Usually, this happens at probe: time; however, the SCSIGeneric driver uses this method at other times.

This method returns a nonzero value if the target/lun pair is already reserved. Otherwise, it returns zero.

See also:  releaseTarget:lun:forOwner:



resetSCSIBus
(sc_status_t)resetSCSIBus

Resets the SCSI bus. Subclasses of IOSCSIController must implement this method so that it resets the SCSI bus. The sc_status_t enumerated type is defined and described in the header file bsd/dev/scsireg.h.



returnFromScStatus:
(IOReturn)returnFromScStatus:(sc_status_t)sc_status

Returns the IOReturn value corresponding to the specified sc_status_t value. The sc_status_t enumerated type is defined and described in the header file bsd/dev/scsireg.h.