<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://trans.onionmixer.net/wiki/index.php?action=history&amp;feed=atom&amp;title=NeXTSTEPDRIVERKIT%3AChapter3_5</id>
	<title>NeXTSTEPDRIVERKIT:Chapter3 5 - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://trans.onionmixer.net/wiki/index.php?action=history&amp;feed=atom&amp;title=NeXTSTEPDRIVERKIT%3AChapter3_5"/>
	<link rel="alternate" type="text/html" href="https://trans.onionmixer.net/wiki/index.php?title=NeXTSTEPDRIVERKIT:Chapter3_5&amp;action=history"/>
	<updated>2026-06-17T08:39:38Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.3</generator>
	<entry>
		<id>https://trans.onionmixer.net/wiki/index.php?title=NeXTSTEPDRIVERKIT:Chapter3_5&amp;diff=5493&amp;oldid=prev</id>
		<title>Onionmixer: NeXTSTEP DRIVER KIT SCSI 컨트롤러 및 주변기기 영문 내용 추가</title>
		<link rel="alternate" type="text/html" href="https://trans.onionmixer.net/wiki/index.php?title=NeXTSTEPDRIVERKIT:Chapter3_5&amp;diff=5493&amp;oldid=prev"/>
		<updated>2017-10-11T10:03:19Z</updated>

		<summary type="html">&lt;p&gt;NeXTSTEP DRIVER KIT SCSI 컨트롤러 및 주변기기 영문 내용 추가&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;;SCSI Controllers and Peripherals&lt;br /&gt;
&lt;br /&gt;
==SCSI 컨트롤러 및 주변기기(SCSI Controllers and Peripherals)==&lt;br /&gt;
&lt;br /&gt;
You can write drivers for both SCSI controllers and SCSI peripherals with the Driver Kit.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Drivers for SCSI controllers should generally be implemented as subclasses of IOSCSIController. Drivers for SCSI devices are indirect drivers that are typically implemented as subclasses of IODevice. These indirect drivers use the IOSCSIControllerExported protocol to communicate with the SCSI controller driver object, which must conform to the IOSCSIControllerExported protocol. (Required protocols and the role they play in connecting drivers are discussed in Chapter 2.)&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Figure 3-1 illustrates the position of SCSI driver classes in the Driver Kit class hierarchy.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For more information on writing a SCSI driver, see the IOSCSIController and IODevice class descriptions.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
An example of a SCSI controller driver is located in &amp;#039;&amp;#039;&amp;#039;/NextDeveloper/Examples/DriverKit/Adaptec1542B&amp;#039;&amp;#039;&amp;#039;. For an example of a SCSI tape drive controller, see &amp;#039;&amp;#039;&amp;#039;NextDeveloper/Examples/DriverKit/SCSITape&amp;#039;&amp;#039;&amp;#039;.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[image:NeXTSTEPDRIVERKIT_09.png|none|thumb|Figure 3-4. Classes for SCSI Controllers]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Development Requirements===&lt;br /&gt;
&lt;br /&gt;
The following hardware is required or recommended for development and support efforts:&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* A workstation with NEXTSTEP User and Developer software&amp;lt;BR&amp;gt;&lt;br /&gt;
* A second NEXTSTEP workstation with NEXTSTEP User software. This is strongly recommended: It&amp;#039;s virtually guaranteed that you&amp;#039;ll corrupt your disk. It&amp;#039;s essentially mandatory if you&amp;#039;re developing a boot driver. Furthermore, the second station allows you to debug the loaded driver at source level. Set up a procedure to quickly recover the contents of your disk.&amp;lt;BR&amp;gt;&lt;br /&gt;
* SCSI Host adapter&amp;lt;BR&amp;gt;&lt;br /&gt;
* Peripherals for testing the adapter: hard disk, CD-ROM, tape drive&amp;lt;BR&amp;gt;&lt;br /&gt;
* SCSI analyzer&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Basic SCSI Controller Driver Operations===&lt;br /&gt;
&lt;br /&gt;
The basic operations needed for a SCSI driver are the following:&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Instantiating and initializing a driver object&amp;lt;BR&amp;gt;&lt;br /&gt;
* Initiating commands&amp;lt;BR&amp;gt;&lt;br /&gt;
* Handling interrupts and command completion&amp;lt;BR&amp;gt;&lt;br /&gt;
* Handling timeouts&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Instantiating and Initializing a Driver Object==== &lt;br /&gt;
&lt;br /&gt;
Override IODevice&amp;#039;s &amp;#039;&amp;#039;&amp;#039;probe:&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;initFromDeviceDescription:&amp;#039;&amp;#039;&amp;#039; methods.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Implement &amp;#039;&amp;#039;&amp;#039;probe:&amp;#039;&amp;#039;&amp;#039; to test for system resources such as I/O ports and to verify the presence of hardware. If the hardware is present, create a driver instance and return YES. If invalid values are found during verification, &amp;#039;&amp;#039;&amp;#039;probe:&amp;#039;&amp;#039;&amp;#039; shouldn&amp;#039;t create an instance; it should instead send an appropriate diagnostic message and return NO.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Your &amp;#039;&amp;#039;&amp;#039;initFromDeviceDescription:&amp;#039;&amp;#039;&amp;#039; method must invoke super&amp;#039;s implementation:&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objc&amp;quot;&amp;gt;&lt;br /&gt;
[super initFromDeviceDescription:deviceDescription];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IOSCSIController&amp;#039;s &amp;#039;&amp;#039;&amp;#039;initFromDeviceDescription:&amp;#039;&amp;#039;&amp;#039; method starts up the default I/O thread provided by IODevice and initializes its instance variables. Your &amp;#039;&amp;#039;&amp;#039;initFromDeviceDescription:&amp;#039;&amp;#039;&amp;#039; method should initialize the hardware state and software structures such as queues and locks.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Initiating Commands===&lt;br /&gt;
&lt;br /&gt;
Implement &amp;#039;&amp;#039;&amp;#039;resetSCSIBus&amp;#039;&amp;#039;&amp;#039; (in the IOSCSIControllerExported protocol) to reset the SCSI bus for your hardware.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Implement &amp;#039;&amp;#039;&amp;#039;executeRequest:buffer:client:&amp;#039;&amp;#039;&amp;#039; (also in the IOSCSIControllerExported protocol). This exported method should convert the command and data (in the IOSCSIRequest struct passed to it) into the format for the specific hardware and place it in a command buffer. Enqueue the buffer in some well-known location--a queuing instance variable you define in your subclass, for example. Send a Mach message with the ID IO_COMMAND_MSG to the I/O thread&amp;#039;s interrupt port to notify the I/O thread that it should execute a command that&amp;#039;s been placed in global data. Wait for the command to complete; you can synchronize this with the I/O thread by using an NXConditionLock object in the command buffer. (For example, you set the lock to a CMD_READY state and then do a &amp;#039;&amp;#039;&amp;#039;lockWhen:&amp;#039;&amp;#039;&amp;#039;CMD_COMPLETE. The I/O thread sets the lock state to CMD_COMPLETE when it&amp;#039;s done. See the example in Chapter 2.) Return SCSI and driver status.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;commandRequestOccurred&amp;#039;&amp;#039;&amp;#039; method is invoked by the I/O thread when it receives a Mach message with the ID IO_COMMAND_MSG. Implement this method to dequeue all commands that have been queued for execution. Send them to the host adapter, using the private methods and functions that you implement for your hardware. If the host adapter isn&amp;#039;t able to accept all the enqueued commands, wait until an interrupt message arrives indicating that the host adapter has completed commands previously sent to it and may now accept more commands.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Handling Interrupts and Command Completion===&lt;br /&gt;
&lt;br /&gt;
When the I/O thread receives a message with the ID IO_INTERRUPT_MSG, it invokes the &amp;#039;&amp;#039;&amp;#039;interruptOccurred&amp;#039;&amp;#039;&amp;#039; method against the driver instance. Your implementation of this method should find all commands that the host adapter has completed, mark their respective command buffers complete, and dequeue them. It should reinvoke the &amp;#039;&amp;#039;&amp;#039;commandRequestOccurred&amp;#039;&amp;#039;&amp;#039; method to process any remaining enqueued commands.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Handling Timeouts===&lt;br /&gt;
&lt;br /&gt;
Just before the I/O thread tells the hardware to execute a command, it should call the &amp;#039;&amp;#039;&amp;#039;IOScheduleFunc()&amp;#039;&amp;#039;&amp;#039; function to arrange for a specified timeout function to be called at a certain time in the future. If the timeout function is called, it sends a Mach message with the ID IO_TIMEOUT_MSG to the I/O thread.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;timeoutOccurred&amp;#039;&amp;#039;&amp;#039; method is invoked by the I/O thread if it receives a message with the ID IO_TIMEOUT_MSG. Your implementation of this method should abort pending commands and reset the SCSI bus.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Other Considerations===&lt;br /&gt;
&lt;br /&gt;
You need to consider a few other issues in implementing a SCSI driver.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Sending Messages to the I/O Thread===&lt;br /&gt;
&lt;br /&gt;
During initialization, get the I/O thread&amp;#039;s interrupt port:&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objc&amp;quot;&amp;gt;&lt;br /&gt;
port = [self interruptPort];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Also get the port&amp;#039;s name in the kernel&amp;#039;s IPC (inter process communication) name space:&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objc&amp;quot;&amp;gt;&lt;br /&gt;
ioTaskPort = IOConvertPort(port, IO_KernelIOTask, IO_Kernel);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Use the &amp;#039;&amp;#039;&amp;#039;msg_send_from_kernel()&amp;#039;&amp;#039;&amp;#039; function to actually send a message from the timeout function or from &amp;#039;&amp;#039;&amp;#039;executeRequest:buffer:client:&amp;#039;&amp;#039;&amp;#039; to the I/O thread. You can&amp;#039;t use &amp;#039;&amp;#039;&amp;#039;msg_send()&amp;#039;&amp;#039;&amp;#039; because when a driver executes outside the I/O task, it no longer has send rights to ports that it had in the I/O task. The same applies to any method or function that you specified in a call to &amp;#039;&amp;#039;&amp;#039;IOScheduleFunc()&amp;#039;&amp;#039;&amp;#039;.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Alignment===&lt;br /&gt;
&lt;br /&gt;
To specify the buffer allocation alignment restrictions that apply to your driver, all you need to do is implement the IOSCSIControllerExported protocol&amp;#039;s method &amp;#039;&amp;#039;&amp;#039;getDMAAlignment&amp;#039;&amp;#039;&amp;#039;, which returns the DMA alignment requirements for the current architecture. This method must fill in all four fields of an IODMAAlignment structure that indicates buffer starting points and total length for reading and writing.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Client drivers can use &amp;#039;&amp;#039;&amp;#039;getDMAAlignment&amp;#039;&amp;#039;&amp;#039; to obtain alignment requirements. They can then use the &amp;#039;&amp;#039;&amp;#039;IOAlign()&amp;#039;&amp;#039;&amp;#039; macro to determine how much memory they really need to allocate. These drivers should do the allocation with &amp;#039;&amp;#039;&amp;#039;allocateBufferofLength:actualStart:actualLength:&amp;#039;&amp;#039;&amp;#039; that allocates well-aligned memory, which is required for calls to &amp;#039;&amp;#039;&amp;#039;executeRequest:buffer:client:&amp;#039;&amp;#039;&amp;#039;.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Mapping Virtual Memory===&lt;br /&gt;
&lt;br /&gt;
This is generally not a concern unless the driver itself must touch data, such as in programmed I/O. In these cases, use &amp;#039;&amp;#039;&amp;#039;IOPhysicalFromVirtual()&amp;#039;&amp;#039;&amp;#039; to get the physical address of the desired data. Of course, there&amp;#039;s no guarantee that you can access every physical address--you only get a valid physical address if the memory is wired down.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Use &amp;#039;&amp;#039;&amp;#039;IOMapPhysicalIntoIOTask()&amp;#039;&amp;#039;&amp;#039; to create a virtual address in the IOTask&amp;#039;s virtual address space. Deallocate this virtual memory by calling &amp;#039;&amp;#039;&amp;#039;IOUnmapPhysicalFromIOTask()&amp;#039;&amp;#039;&amp;#039;.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Maximum Data Transfer===&lt;br /&gt;
&lt;br /&gt;
If you implement the method &amp;#039;&amp;#039;&amp;#039;maxTransfer&amp;#039;&amp;#039;&amp;#039;, it may simplify your design. Upper layers can use the value returned by this method to determine the maximum data transfer size your driver can handle. They won&amp;#039;t try to send commands that attempt to transfer more data than the driver can handle.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Statistics===&lt;br /&gt;
&lt;br /&gt;
A suite of methods such as &amp;#039;&amp;#039;&amp;#039;maxQueueLength&amp;#039;&amp;#039;&amp;#039; are available to return statistics used by &amp;#039;&amp;#039;&amp;#039;iostat&amp;#039;&amp;#039;&amp;#039; and other commands. The example located in &amp;#039;&amp;#039;&amp;#039;/NextDeveloper/Examples/DriverKit/Adaptec1542B&amp;#039;&amp;#039;&amp;#039; illustrates gathering these statistics.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===SCSI Peripheral Drivers===&lt;br /&gt;
&lt;br /&gt;
To write a SCSI peripheral device driver, create a subclass of IODevice. Use the methods in the IOSCSIControllerExported protocol to allow the SCSI peripheral driver object to talk to the SCSI controller object. Some of this protocol&amp;#039;s key methods include:&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;executeRequest:buffer:client:&amp;#039;&amp;#039;&amp;#039;, which sends SCSI commands to a peripheral device.&amp;lt;BR&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;getDMAAlignment:&amp;#039;&amp;#039;&amp;#039;, which returns DMA alignment requirements.&amp;lt;BR&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;allocateBufferOfLength:actualStart:actualLength:&amp;#039;&amp;#039;&amp;#039;, which allocates and returns a pointer to well-aligned memory, required for invoking &amp;#039;&amp;#039;&amp;#039;executeRequest:buffer:client:&amp;#039;&amp;#039;&amp;#039;. It&amp;#039;s used with other alignment functions such as &amp;#039;&amp;#039;&amp;#039;IOAlign()&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;getDMAAlignment:&amp;#039;&amp;#039;&amp;#039;.&amp;lt;BR&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;reserveTarget:lun:forOwner:&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;releaseTarget:lun:forOwner:&amp;#039;&amp;#039;&amp;#039;, which respectively reserve and release a specified target/lun pair.&amp;lt;BR&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;resetSCSIBus&amp;#039;&amp;#039;&amp;#039;, which resets the SCSI bus.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Implement the &amp;#039;&amp;#039;&amp;#039;probe:&amp;#039;&amp;#039;&amp;#039; method to get the &amp;#039;&amp;#039;&amp;#039;id&amp;#039;&amp;#039;&amp;#039; of the SCSI controller object from the IODeviceDescription object that&amp;#039;s handed to &amp;#039;&amp;#039;&amp;#039;probe:&amp;#039;&amp;#039;&amp;#039; as its parameter. In addition, probe: may send a SCSI INQUIRY command to each target/lun pair on its controller to see if a peripheral supported by the driver is connected to the SCSI bus. For every peripheral it finds, &amp;#039;&amp;#039;&amp;#039;probe:&amp;#039;&amp;#039;&amp;#039; should instantiate a SCSI peripheral driver object.&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For an example of a SCSI tape drive controller, see &amp;#039;&amp;#039;&amp;#039;/NextDeveloper/Examples/DriverKit/SCSITape&amp;#039;&amp;#039;&amp;#039;.&amp;lt;BR&amp;gt;&lt;/div&gt;</summary>
		<author><name>Onionmixer</name></author>
	</entry>
</feed>