Copyright ã1994 by Christopher Wolf
($Id: SCSI.rtf,v 0.11 94/12/07 04:04:32 chris Exp $)

SCSI

Inherits From:	Object

Declared In:	SCSI2_Class/Source/SCSI.h 

Class Description

The SCSI class is used to communicate with SCSI 2 devices and serves as a super-class for additional sub-classes for interacting with specific device types.  SCSI class contains methods for opening and closing the SCSI device driver, selecting the SCSI target ID, finding a device of a specific type, retrieving error and status information, sending low-level SCSI requests and sending generic pre-packaged SCSI commands which apply to all device types.

Concepts and Examples

The SCSI class can use either the generic SCSI driver (sg0) or a specific SCSI based device driver (/dev/st0, /dev/mt0, /dev/sd0, etc) to perform SCSI access.   The driver must be opened before commands can be issued and closed as soon as access is finished so that other processes can gain access to it if necessary.   If you wish to use a device driver other than the generic SCSI device driver you must explicitly select that device driver using the setDriver:ioctrlCode: or openDriver:ioctlCode methods.  The openSCSI and closeSCSI methods will open the currently selected device driver or the generic SCSI driver (sg) if no other device driver has been specifically selected.   The setTarget:lun: method is used to select a target SCSI ID and logical unit number to be addressed when using the generic SCSI device driver.  The isOpen method allows you to check whether a SCSI driver is currently open.  It is an error to a SCSI  driver if another SCSI driver has already been opened by this instance.  It is an error to close an already closed driver.

The SCSI class contains a set of pre-packaged SCSI command methods which open the driver, build the necessary command structures, issue the command and then close the driver.  When using these pre-packaged SCSI command methods the calling object does not have to worry about opening and closing the driver or about any of the internal details of the SCSI command structures.  However the  SCSI class still must be informed which driver to use before calling any pre-packaged commands.  If the generic SCSI driver is to be used the setTarget:lun: method must be called to select a target (SCSI ID) and lun before issuing any SCSI commands.  If a specific non-generic device driver is to be used the setDevice:ioctlCode: method must be called before issuing any SCSI commands.  The following code fragment illustrates how simple it is to use pre-packaged command methods with the SCSI generic device driver:

//
// Example 1.
//
// Example code fragment showing how to use one of the pre-packaged SCSI command
// methods provided by the SCSI class to perform a SCSI Inquiry on a device 
// attached at SCSI ID 0, logical unit number 0 using the generic (sg) driver. 
//

#import "SCSI.h"                  // import SCSI class interface file
#import "scsi2reg.h"              // import additional structure definitions

struct inquiry_reply irbuffer;    // structure to hold inquiry results

scsi = [[SCSI alloc] init];       // instantiate the class

[scsi setTarget: 1 lun: 0];       // select device at ID 1, lun 0 
[scsi inquiry: &irBuffer];        // issue the "inquiry: command to that device

// do something with the inquiry results here

[scsi free];                      // release resources

Many common SCSI commands are implemented as pre-packaged command methods but if you want to send a SCSI command which does not exist as a prepackaged method this is still possible.  You must build the command structures yourself and then pass them to the executeRequest: method of the SCSI class.  If you are issuing a SCSI command in this manner then it is your responsibility to open and close the SCSI device.  The following code fragment illustrates the basic procedure for building and issuing your own SCSI commands:

//
// Example 2.
//
// Example code fragment showing how to use low-level methods to issue the
// same Inquiry command as example 1.  We could have used the pre-packaged
// method (and normally SHOULD if one exists) but this is for illustration
// and comparison purposes.
//

#import "SCSI.h"                                   // import SCSI class interface file
#import "scsi2reg.h"                               // import additional structure definitions

struct inquiry_reply irbuffer;                     // structure to hold inquiry results
struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;            // SCSI command block
struct scsi_req sr;                                // SCSI request structure		
scsi = [[SCSI alloc] init];                        // instantiate the class 
[scsi openSCSI];                                   // we must open the device ourself
[scsi setTarget: 1 lun: 0];                        // select device at ID 1, lun 0

// initializes the command blocks
[SCSI clearCommandBlock: (union cdb *) cdbp];      // clear the command block
cdbp->c6_opcode = C6OP_INQUIRY;                    // specify opcode
cdbp->c6_lun    = lun;                             // specify logical unit number
cdbp->c6_len    = 36;                              // specify length

// initialize the SCSI request
sr.sr_dma_dir = SR_DMA_RD;                         // specify DMA direction
sr.sr_addr    = (char *) irbuffer;                 // specify DMA destination 
sr.sr_dma_max = 36;                                // specify DMA length
sr.sr_ioto    = 30;                                // specify IO timeout

[scsi executeRequest: &sr];                        // tell SCSI class to execute the request
[scsi closeSCSI];                                  // close device as soon as we are done

// do something with the inquiry results here

[scsi free];                                       // release resources 

Note that for clarity's sake the above examples do not perform any error checking or reporting.  Almost all of the SCSI class methods will return 0 for success or a non-zero value for error.   In real-world programs return codes should always be checked.  If a non-zero error indicator is returned several instance methods are provided for retrieving various additional error information.

The SCSI standard assumes that all multi-byte integer values are specified in big-endian byte order (most significant byte first.)  On Motorola machines, which are natively big-endian, this is not a problem.  However this does cause complications on Intel machines which store integers in little endian format (least significant byte first).  Thus special procedures must be followed when reading from or writing to multi-byte integer elements in structures defined by the SCSI standard (structures in <bsd/dev/scsireg.h> and "scsi2reg.h").  The SCSI class provides a set of functions for dealing with this situation.  These functions automatically determine what architecture the code is running on and perform the necessary conversions.  Use these functions whenever reading or writing multi-byte values to SCSI structures in order to ensure that your code will work on both Intel and Motorola hardware.  (Note that multi-byte elements in structures defined in "scsi2reg.h" are flagged by prepending the letters BE_ to the structure element name.  This is not done for you in structures defined in the older <bsd/dev/scsireg.h> header file) so care must be taken to recognize instances where it is necessary to use the special functions to access structure elements.  The following code fragment illustrates how to use these functions:

//
// Example 3.
//
// Example code fragment showing how to use the SCSI class functions to
// correctly interpret a multi-byte value in an architecture independent
// manner. 
//

#import "SCSI.h"                                   // import SCSI class interface file
#import "scsi2reg.h"                               // import additional structure definitions

struct capacity_reply crbuffer;                    // structure to hold inquiry results

// issue a read capacity command
scsi = [[SCSI alloc] init];                        // instantiate the class
[scsi setTarget: 1 lun: 0];                        // select device at ID 1, lun 0
[scsi readCapacity: &crBuffer];                    // issue the ReadCapacity command 

numBlocks = readBigEndianLong(&cr.cr_lastlba_BE32);// multi-byte value so we must use function!
printf("Number of blocks on device %d",numBlocks); // print results

[scsi free];                                       // release resources

Additional Information

For additional information about specifics of the SCSI standard or SCSI command structures see the draft copy of the SCSI 2 standard which is provided in electronic form along with this class archive.

For a complete example of how to use the SCSI class see the source code to SCSI_Inspector.app which also should be included with this archive.   The source code is a bit sparsely commented but should still be fairly straightforward to understand.  It demonstrates many valuable techniques for writing correct SCSI code which will function on both Motorola and Intel hardware.

For an example of how to implement a sub-class of the SCSI class see the DriveSCSI class provided with this archive.  The DriveSCSI source code can easily be used as a skeleton for different device type sub-classes.  

The source code to the SCSI class itself  is provided as the ultimate authority on how the class works.  It is actually pretty well commented, especially the "scsi2reg.h" header file.

See the README file for information about how to contact the author for any remaining questions, comments or feedback.

Instance Variables

BOOL isOpen;
int target;
int lun;
int fd;
int ioctlCode;
BOOL immed;
int timeout;
char *dev_name;
struct scsi_req sr;
struct scsi_addr sa;
PrintFunction dprintf;
char errorString[100];

isOpen	TRUE if SCSI driver is open, FALSE otherwise.

target	SCSI ID of the currently selected target (0-7) for generic SCSI device (sg).

lun	Currently selected Logical Unit Number (0-7) for generic SCSI device (sg)

fd	File descriptor for the SCSI device driver.

ioctlcode	Request code to use for ioctl when issuing commands to the device driver. 

immed	Indicates long commands should return immediately

timeout	Timeout delay for commands.

dev_name	File name for the current SCSI device driver.

sr	SCSI command request parameters.

sa	SCSI command address parameters.

dprintf	Debugging/error information print function.

errorString 	English language SCSI class error information.

Method Types

Set and Read Instance Variables	±  setImmediate:
	±  immediate
	±  setTimeout:
	±  timeout

Open, Close, Select a Device  	±  openDevice:ioctlCode:	
	±  openTarget:lun:
	±  setDevice:ioctlCode:
	±  setTarget:lun:
	±  openSCSI
	±  closeSCSI

Locate a Device  	±  findDevice
	±  findDevice:
	±  isDevice

Retrieve/Display Status Info	+ dprintf
	+ setDprintf
	±  isOpen
	±  fd
	±  errorString
	±  statusReq
	±  returnDriverStatus:scsiStatus:andExtendedSense
	±  returnError:

Send Pre-packaged Commands 	-  inquiry:
-  readCapacity:
±  requestSense:
±  testUnitReady
±  receiveDiagnostic:size:
±  sendDiagnostic:size:pf:st:dol:uol:
±  modeSenseRaw:size:page:pc:dbd:
±  modeSenseCooked:size:page:
±  modeSelectRaw:size:save:

Send Low-level Commands 	+ clearCommandBlock:
-  executeRequest:
±  executeBusReset

Class Methods

clearCommandBlock:
+ clearCommandBlock:(union cdb *)cdbp

This zeroes out all the bits in cdbp in preparation for a command request.  The union structure cdb  is defined in "scsi2reg.h".  This is a low level method which should only be used by subclasses of SCSI or objects which are sending their own low-level SCSI commands using the executeRequest: or performRequest methods.   

See also:  ±  executeRequest:, ±  performRequest 

dprintf
+ (PrintFunction)dprintf 

This method returns a pointer to the currently selected error and debug message PrintFunction.  See the setDprintf: method description for a complete explanation of PrintFunctions.

See also:  +  setDprintf

setDprintf
+ setDprintf:(PrintFunction)pf 

This method allows the programmer to specify which PrintFunction will be used to display error and debugging messages from the SCSI class and its sub-classes.   The PrintFunction typedef is defined in SCSI.h.  A PrintFunction is is a function which accepts printf style parameters (a format string followed by a parameter list) and displays the formatted output to a particular place.  The programmer can specify a custom PrintFunction or use one of the following pre-programmed PrintFunctions included in errio.c:

     printfToStderr - sends formatted output to stderr
     printfToStdout - sends formatted output to stdou
     printfToSysLog - sends formatted output to system log
     printfToNull - a do nothing PrintFunction stub  

The default PrintFunction is printfToStdErr.  A pointer to the currently selected PrintFunction can be retrieved using the dprintf method.

Note to sub-class implementers:  Internally, the pointer to the currently selected PrintFunction is stored in the dprintf instance variable of the SCSI class.   In order for SCSI sub-class error messages to be properly redirected via the setDprintf method, sub-classes should always use the function pointer in the dprintf instance variable to display error and debugging messages.  For example:

	// display an error or debug message
	dprintf("Your error message here, value: %d string: %s",1,"Hi!");

See also:  +  dprintf

Instance Methods

closeSCSI
- (int)closeSCSI

Closes the currently open SCSI driver.  This is required in order to release the SCSI driver so that other programs can use it.  The SCSI driver should be kept open for as short a period of time as possible.  The pre-packaged command methods take care of opening and closing the SCSI driver for you.  This method returns 0 if successful, non-zero if there was an error.  It is an error to attempt to close the SCSI driver if it is not open.

See also:  ±  openSCSI, ± openDevice:, ±  openTarget:lun:, ±  isOpen, ±  errorString 

errorString
- (char *)errorString

Returns the errorString instance variable which holds information (in ASCII format) about the last error. It is the responsibility of subclasses of SCSI to put the proper information in errorString when an error occurs. The SCSI class will not return errors in errorString for you. To access bus level errors use the sr return codes or use returnError: to interpret the sr return codes for you.  

See also:  ±  statusReq, ±  returnError:, ±  returnDriverStatus:scsiStatus:andExtendedSense: 

executeBusReset
- (int)executeBusReset

This method performs a software RESET of the SCSI bus. It can only be performed by someone running as the superuser and should be used cautiously. See the sg (4) manual page for more information.  Returns 0 for success, non-zero for error.

executeRequest:
- (int)executeRequest:(struct scsi_req *)sp

This method calls the SCSI driver with the parameters as set  in the structure sp (defined in <bsd/dev/scsireg.h>). This is a low level method which should only be called by other objects which wish to make SCSI driver command requests. Error codes, if any, will be returned in the sp structure in the predetermined places.  This method does NOT open or close the SCSI device for the caller.

fd
- (int)fd

Returns the file descriptor of the currently open SCSI device driver or -1 if no driver is open.

See also:  ± isOpen

findDevice
- (int)findDevice

This method sequentially steps through the SCSI targets calling the isDevice: method for each target.  This method returns the number of the first target which responds TRUE to isDevice, or -1 if none responds TRUE.  Remember that isDevice is over-ridden by sub-class implementations.  This means that for instances of the SCSI super class findDevice will return the number of the first valid SCSI target of any type;  for instances of a specific sub-class findDevice will return the number of the first device which that sub-class type recognizes.

See also:  ±  findDevice:,  ±  isDevice:

findDevice:
- (int)findDevice:(int)trg

This method works like findDevice: but starts searching from the specified target instead of at target 0.

See also:  ±  findDevice,  ±  isDevice:

immediate
- (BOOL)immediate 

If this method returns TRUE then immediate command execution mode is currently enabled (the default).  If this method returns FALSE immediate mode execution is disabled and you may have to adjust the timeout to allow sufficient time for execution of lengthy commands such as FORMAT UNIT.

See also:  ±  setTimeout:, ±  setImmediate:

inquiry:
- (int)inquiry:(struct inquiry_reply *)ibuffer

This is a pre-packaged SCSI command method which sends the Inquiry command (group 0, code 0x12) to the current target device.  Inquiry data will be returned in the inquiry_reply structure defined in "scsi2reg.h".  This method will return 0 if successful or non-zero if there was an error.  

Since this is a pre-packaged command method it takes care of all the messy low-level details of building and sending the SCSI request.  It is not necessary for the SCSI device to be open before calling this method.  If the SCSI device was open when this method was called the device will remain open after the method exits.  

isDevice
- (BOOL)isDevice

Returns TRUE if the current target device is a SCSI device, FALSE if there is no device present.  This method is called by findDevice and findDevice: methods to identify the first available SCSI target.  This method is intended to be over-ridded by SCSI sub-classes in order to identify if a SCSI device of a specific type is present so that findDevice or findDevice: methods, when called from a sub-class, will identify the first device that is of the type which the sub-class handles.

See also:  ± findDevice:, ±  findDevice 

isOpen
- (BOOL)isOpen

Returns TRUE if the SCSI device driver is open and accessible, FALSE otherwise.

See also:  ± openSCSI, ±  closeSCSI,  ±  openTarget:lun:, ±  openDevice:ioctlCode:

modeSelectRaw:size:save:
- (int)modeSelectRaw:(mode_parameter_list *)mpl size:(u_char)size save:(BOOL)save 

This is a pre-packaged SCSI command method which implements the Mode Select command  The data for the mode select operation must be passed in a mode parameter list in a buffer of length size pointed to by mpl.  If the save parameter is specified TRUE the mode select command will inform the device to store the new page data in its non-volatile memory, if the device supports this.  The mode parameter list structure is defined in "scsi2reg.h" and the SCSI 2 specification.    Remember to set all reserved fields to NULL and to supply only valid parameters in the mode parameter list pages or this call will probably fail.  Be CAREFUL!
This method will return 0 if successful or non-zero if there was an error.   

Since this is a pre-packaged command method it takes care of all the messy low-level details of building and sending the SCSI request.  It is not necessary for the SCSI device to be open before calling this method.  If the SCSI device was open when this method was called the device will remain open after the method exits. 

See also:  ± modeSenseRaw:size:page:pc:dbd:, ±  modeSenseCooked:size:page:pc:

modeSenseCooked:size:page:pc:
- (int)modeSenseCooked:(mode_page *)mp size:(u_char)size page:(u_char )page pc:(u_char)pc 

This is a pre-packaged SCSI command method which implements the Mode Sense command (group 0, code 0x1a).  Just the requested mode sense page (without mode parameter headers or block descriptors) is returned in the buffer pointed to by mp of size size.    pc is the page control value which determines if default or current page settings are returned.  It is the caller's responsibility to interpret the mode page data according to the structures defined in "scis2reg.h" and the SCSI 2 specification. This method will return 0 if successful or non-zero if there was an error.   

Since this is a pre-packaged command method it takes care of all the messy low-level details of building and sending the SCSI request.  It is not necessary for the SCSI device to be open before calling this method.  If the SCSI device was open when this method was called the device will remain open after the method exits. 

See also:  ± modeSenseRaw:size:page:pc:dbd:, ±  modeSelectRaw:size:save:

modeSenseRaw:size:page:pc:dbd:
- (int)modeSenseRaw:(mode_parameter_list *)mpl size:(u_char)size page:(u_char )page pc:(u_char)pc dbd:(BOOL)dbd 

This is a pre-packaged SCSI command method which implements the Mode Sense command (group 0, code 0x1a).  A complete mode parameter list structure will be returned in the buffer of length size pointed to by mpl.   The mode parameter list will always include a mode parameter header and the specified mode page.   If dbd (disable block descriptors) is FALSE the mode parameter list may also include one or more block descriptors.   pc is the page control value which determines if default or current page settings are returned.  It is the caller's responsibility to interpret the mode parameter list according to the structures defined in "scsi2reg.g" and the SCSI 2 specification.  This method will return 0 if successful or non-zero if there was an error.   

Since this is a pre-packaged command method it takes care of all the messy low-level details of building and sending the SCSI request.  It is not necessary for the SCSI device to be open before calling this method.  If the SCSI device was open when this method was called the device will remain open after the method exits. 

See also:  ± modeSenseCooked:size:page:pc:, ± modeSelectRaw:size:save:

openDevice:ioctlCode:
- (int)openDevice:(const char *)deviceName ioctlCode:(int)ioctlCode

Opens a specified SCSI based device driver such as "/dev/st0", "/dev/mt0", "/dev/sd0" etc.   If you want to use the generic "sg" device driver use the OpenTarget:lun: method instead!   The ioctlCode parameter specifies what request value will be used in the request field of ioctl function calls used to send SCSI commands to this device.    Possible values for this field are defined in "scsi2reg.h"   For example,  for generic SCSI devices the request type is SGIOCTLREQ, for tape devices it's MTIOCSRQ, for disk type devices it's DKIOCREQ.  The SCSI driver should be kept open for as short a time as possible. Pre-packaged command methods implemented in this class automatically open and close the SCSI driver, if necessary.  If using pre-packaged command methods with a device OTHER than the generic SCSI device the setDevice:ioctlCode: method must be called previous to issuing any pre-packaged commands in order to specify the correct device and ioctl code to use.   Returns 0 if successful, non-zero if there was an error. 

See also:  ± openSCSI,  ± closeSCSI, ±  setDevice:ioctlCode:,  - openTarget:lun:

openSCSI
- (int)openSCSI

Opens the currently selected SCSI device driver.   If a specific SCSI device driver has been previously specified with the setDriver:ioctlCode: method then that SCSI device driver will be opened.  Otherwise the first avaible generic SCSI device driver (sg) will be opened.  If you are using the generic device driver you must remember to select a target and lun with setTarget:lun: before issuing any SCSI commands.  The SCSI device driver should be kept open for as short a time as possible.  Pre-packaged command methods implemented in this class automatically open and close the SCSI driver if necessary.  It is an error to attempt to open any SCSI device if the instance already has another SCSI device open.  Returns 0 if successful, non-zero if there was an error.

See also:  ± openTarget:lun:,  ± openDevice:ioctlCode:, ±  setTarget:lun:, ± setDevice:ioctlCode:, ± closeSCSI

openTarget:lun:
- (int)openTarget:(int)trg lun:(int)ln

This method combines the openSCSI and setTargetSCSI: lun: methods so that the SCSI generic device driver can be opened and a target and lun selected with a single method call.  This is the preferred method of opening the generic SCSI driver since it forces selection of a target which you MUST remember to do (using either this method or setTarget:lun:) before issuing any SCSI commands.  Returns 0 if successful, non-zero if there was an error. 

See also:  ± openSCSI,  ± openDevice:ioctlCode:, ±  setTarget:lun:

readCapacity:
- (int)readCapacity:(struct capacity_reply *)rbuffer

This is a pre-packaged SCSI command method which sends the Read Capacity command (group 1, code 0x25) to the current target device.  Capacity data will be returned in the capacity2_reply structure defined in "scsi2reg.h".  This method will return 0 if successful or non-zero if there was an error.  

Since this is a pre-packaged command method it takes care of all the messy low-level details of building and sending the SCSI request.  It is not necessary for the SCSI device to be open before calling this method.  If the SCSI device was open when this method was called the device will remain open after the method exits.  

receiveDiagnostic:size:
- (int)receiveDiagnostic:(char *)buffer size:(u_char)size

This is a pre-packaged SCSI command method which sends the Receive Diagnostic command (group 0, code 0x1c) to the current target device.  This method must be passed a pointer to a pre-allocated buffer where diagnostic data will be returned and the length of that buffer (in size).  This method will return 0 if successful or non-zero if there was an error.  

Since this is a pre-packaged command method it takes care of all the messy low-level details of building and sending the SCSI request.  It is not necessary for the SCSI device to be open before calling this method.  If the SCSI device was open when this method was called the device will remain open after the method exits.  

See also:  ± sendDiagnostic:size:pf:st:dol:uol:

requestSense:
- (int)requestSense:(struct esense_reply *)ebuffer

This is a pre-packaged SCSI command method which sends the Request Sense command (group 0, code 0x03) to the current target device.  Sense will be returned in the esense_reply structure defined in "scsi2reg.h".  This method will return 0 if successful or non-zero if there was an error.  

Since this is a pre-packaged command method it takes care of all the messy low-level details of building and sending the SCSI request.  It is not necessary for the SCSI device to be open before calling this method.  If the SCSI device was open when this method was called the device will remain open after the method exits.  

returnDriverStatus:scsiStatus:andExtendedSense:
- (char *)returnDriverStatus:(char **)driverStatus scsiStatus:(char **)scsiStatus andExtendedSense:(char **) extendedSense

This method places interpreted versions of the sr error codes, including the extended sense error codes if valid, into the character strings that were given to it (also returns a pointer to a buffer containing all three strings concatenated into one). The format of the returned strings is not strict and should be only used for debugging purposes.  The actual error codes are more or less taken from <nextdev/scsireg.h>. This method is intended mostly as an easy way to provide debugging information.

See also:  ± statusReq, ± errorString,  ±  returnError:

returnError: 
- (char *)returnError: sender

This method places interpreted versions of the sr error codes, including the extended sense error codes if valid, into a single concatenated string.  The format of the returned string is not strict and should be only used for debugging purposes.  The actual error codes are more or less taken from <nextdev/scsireg.h>. This method is just a wrapper for returnDriverStatus:scsiStatus:andExtendedSense:.

See also:  ± statusReq, ± errorString, ±  returnDriverStatus:scsiStatus:andExtendedSense: 

sendDiagnostic:size:pf:st:dol:uol:
- (int)sendDiagnostic:(char *)buffer size:(u_char)size pf:(BOOL)pf st:(BOOL)st dol:(BOOL)dol uol:(BOOL)uol

This is a pre-packaged SCSI command method which sends the Send Diagnostic command (group 0, code 0x1d) to the current target device using the parameters specified in the method call.   pf indicates if the command format is compliant with the SCSI2 specification page format.  st indicates whether the device should perform its self-test.  dol and uol stand for device off line and unit off line respectively.   For a more complete definition of the meaning of the various parameters consult the SCSI specification.   Results will be returned in a pre-allocated buffer of length size at address buffer.  This method will return 0 if successful or non-zero if there was an error.  

Since this is a pre-packaged command method it takes care of all the messy low-level details of building and sending the SCSI request.  It is not necessary for the SCSI device to be open before calling this method.  If the SCSI device was open when this method was called the device will remain open after the method exits.  

See also:  ±  receiveDiagnostic:size:

setDevice:ioctlCode:
- (int)setDevice:(const char *)deviceName ioctlCode:(int)ioctlCode

This method specifies that a device driver other than the generic SCSI device driver should be opened by the next openSCSI method call.   The setDevice:ioctlCode: method must be used prior to calling the open method or any pre-packaged SCSI command methods.   If you wish to use the generic SCSI device driver (sg) use the setTarget:lun: method instead.   The ioctlCode parameter specifies what request value will be used in the request field of ioctl function calls used to send SCSI commands to this device.    For example,  for generic SCSI devices the request type is SGIOCTLREQ, for tape devices it's MTIOCSRQ, for disk type devices it's DKIOCREQ.   Possible values for this field are defined in "scsi2reg.h"  Returns 0 if successful, non-zero if there was an error.   The error value returned by this method is semi-meaningless since we don't know for sure if the selected device can be successfully opened until we actually try to open it via the openSCSI method. 

See also:  ±  openDevice:ioctlCode:, ± openSCSI

setImmediate:
- setImmediate:(BOOL)immediate 

If setImmediate: TRUE is used lengthy commands (such as FORMAT UNIT) will be executed in immediate mode and return as soon as the device successfully acknowledges the command without necessarily waiting for the command to complete.  If  setImmediate: FALSE is used all commands will not return until they have been entirely completed by the target device.  The default is immediate command execution.  If immediate execution is disabled you may have to adjust the timeout value (using setTimeout:) since the default 30 second SCSI command timeout may not be sufficient to allow lengthy commands such as a FORMAT UNIT to complete.

See also:  ±  setTimeout:, ±  immediate

setTarget:lun:
- (int)setTarget:(int)trg lun:(int)ln

This method is only used if the generic SCSI device driver is being used.  Selects the indicated target (SCSI ID) and logical unit number for subsequent SCSI requests.  The target and lun may be set using this method either before or after an openSCSI method call.  The target MUST be set, using this method or the openTarget:lun: method before any SCSI commands are issued and before any pre-packaged command methods are called.  This method does NOT actually check to make sure that there is a recognized device at the specified location it just checks to make sure the values specified are within the valid range of 0-7.  This method (and the SCSI class in general) has not been tested with logical unit numbers other than zero.  Returns 0 for success or non-zero for error.

See also:  ±  openTarget:lun:, ±openSCSI

setTimeout:
- setTimeout:(int)seconds 

This method sets the timeout delay used by SCSI pre-packaged command methods.  The timeout defaults to 30 seconds if it is not explicitly set which should be plenty of time for most SCSI commands to complete.

See also:  ±  timeout, ±  setImmediate:

statusReq
- (struct scsi_req *)statusReq

This returns the status of the last SCSI request as a pointer to a scsi_req structure defined in "scsi2reg.h".

See also:  ± errorString, ±  returnError, ±  returnDriverStatus:scsiStatus:andExtendedSense: 

testUnitReady
- (int)testUnitReady 

This is a pre-packaged SCSI command method which sends the Test Unit Ready command (group 0, code 0x00) to the current target device.  This method will return 0 if the target is ready or non-zero if there was an error or the target is not ready.

Since this is a pre-packaged command method it takes care of all the messy low-level details of building and sending the SCSI request.  It is not necessary for the SCSI device to be open before calling this method.  If the SCSI device was open when this method was called the device will remain open after the method exits.  

timeout
- (int)timeout 

This method returns the current tiemout delay used by SCSI pre-packaged command methods.  The timeout defaults to 30 seconds if it is not explicitly set which should be plenty of time for most SCSI commands to complete.

See also:  ±  setTimeout, ±  setImmediate: