📄 cds.txt
字号:
Linux/390Common Device Support (CDS)Device Driver I/O Support RoutinesAuthor : Ingo AdlungCopyright, IBM Corp. 1999IntroductionThis document describes the common device support routines for Linux/390.Different than other hardware architectures, ESA/390 hasdefined a unifiedI/O access method. This gives relief to the device drivers as they don'thave to deal with different bus types, polling versus interruptprocessing, shared versus non-shared interrupt processing, DMA versus portI/O (PIO), and other hardware features more. However, this implies thateither every single device driver needs to implement the hardware I/Oattachment functionality itself, or the operating system provides for aunified method to access the hardware, providing all the functionality thatevery single device driver would have to provide itself.The document does not intend to explain the ESA/390 hardware architecture inevery detail.This information can be obtained from the ESA/390 Principles ofOperation manual (IBM Form. No. SA22-7201).In order to build common device support for ESA/390 I/O interfaces, afunctional layer was introduced that provides generic I/O access methods tothe hardware. The following figure shows the usage of the common device supportof Linux/390 using a TbCP/IP driven device access an example. Similar figurescould be drawn for other access methods, e.g. file system access to diskdevices.The common device support layer shown above comprises the I/O support routinesdefined below. Some of them implement common Linux device driver interfaces,while some of them are ESA/390 platform specific.get_dev_info_by_irq() / get_dev_info_by_devno() allow a device driver to determine the devices attached (visible) to the system and their current status.get_irq_by_devno() / get_devno_by_irq() get irq (subchannel) from device number and vice versa.read_dev_chars() read device characteristicsrequest_irq() obtain ownership for a specific device.free_irq() release ownership for a specific device.disable_irq() disable a device from presenting interrupts.enable_irq() enable a device, allowing for I/O interrupts.do_IO() initiate an I/O request.halt_IO() terminate the current I/O request processed on the device.do_IRQ() generic interrupt routine. This function is called by the interrupt entry routine whenever an I/O interrupt is presented to the system. The do_IRQ() routine determines the interrupt status and calls the device specific interrupt handler according to the rules (flags) defined during I/O request initiation with do_IO().The next chapters describe the functions, other than do_IRQ() in more details.The do_IRQ() interface is not described, as it is called from the Linux/390first level interrupt handler only and does not comprise a device drivercallable interface. Instead, the functional description of do_IO() alsodescribes the input to the device specific interrupt handler.Common Device Support (CDS) for Linux/390 Device DriversGeneral InformationThe following chapters describe the I/O related interface routines theLinux/390 common device support (CDS) provides to allow for device specificdriver implementations on the IBM ESA/390 hardware platform. Those interfacesintend to provide the functionality required by every device driverimplementaion to allow to drive a specific hardware device on the ESA/390platform. Some of the interface routines are specific to Linux/390 and someof them can be found on other Linux platforms implementations too.Miscellaneous function prototypes, data declarations, and macro definitionscan be found in the architecture specific C header filelinux/arch/s390/kernel/irq.h.Overview of CDS interface conceptsDifferent to other hardware platforms, the ESA/390 architecture doesn't defineinterrupt lines managed by a specific interrupt controller and bus systemsthat may or may not allow for shared interrupts, DMA processing, etc.. Instead,the ESA/390 architecture has implemented a so called channel subsystem, thatprovides a unified view of the devices physically attached to the systems.Though the ESA/390 hardware platform knows about a huge variety of differentperipheral attachments like disk devices (aka. DASDs), tapes, communicationcontrollers, etc. they can all by accessed by a well defined access method andthey are presenting I/O completion a unified way : I/O interruptions. Everysingle device is uniquely identified to the system by a so called subchannel,where the ESA/390 architecture allows for 64k devices be attached.Linux, however was first built on the Intel PC architecture, with its twocascaded 8259 programmable interrupt controllers (PICs), that allow for amaximum of 15 different interrupt lines. All devices attached to such a systemshare those 15 interrupt levels. Devices attached to the ISA bus system mustnot share interrupt levels (aka. IRQs), as the ISA bus bases on edge triggeredinterrupts. MCA, EISA, PCI and other bus systems base on level triggeredinterrupts, and therewith allow for shared IRQs. However, if multiple devicespresent their hardware status by the same (shared) IRQ, the operating systemhas to call every single device driver registered on this IRQ in order todetermine the device driver owning the device that raised the interrupt.In order to not introduce a new I/O concept to the common Linux code,Linux/390 preserves the IRQ concept and semantically maps the ESA/390subchannels to Linux as IRQs. This allows Linux/390 to support up to 64kdifferent IRQs, uniquely representig a single device each.During its startup the Linux/390 system checks for peripheral devices. Eachof those devices is uniquely defined by a so called subchannel by the ESA/390channel subsystem. While the subchannel numbers are system generated, eachsubchannel also takes a user defined attribute, the so called device number.Both, subchannel number and device number can not exceed 65535. Theinit_IRQ() routine gathers the information about control unit type and devicetypes that imply specific I/O commands (channel command words - CCWs) inorder to operate the device. Device drivers can retrieve this set of hardwareinformation during their initialization step to recognize the devices theysupport using get_dev_info_by_irq() or get_dev_info_by_devno() respectively.This methods implies that Linux/390 doesn't require to probe for free (notarmed) interrupt request lines (IRQs) to drive its devices with. Whereapplicable, the device drivers can use the read_dev_chars() to retrieve devicecharacteristics. This can be done without having to request device ownershippreviously.When a device driver has recognized a device it wants to claim ownership for,it calls request_irq() with the device's subchannel id serving as pseudo irqline. One of the required parameters it has to specify is dev_id, defining adevice status block, the CDS layer will use to notify the device driver'sinterrupt handler about interrupt information observed. It depends on thedevice driver to properly handle those interrupts.In order to allow for easy I/O initiation the CDS layer provides a do_IO()interface that takes a device specific channel program (one or more CCWs) asinput sets up the required architecture specific control blocks and initiatesan I/O request on behalf of the device driver. The do_IO() routine allows fordifferent I/O methods, synchronous and asynchronous, and allows to specifywhether it expects the CDS layer to notify the device driver for everyinterrupt it observes, or with final status only. It also provides a schemeto allow for overlapped I/O processing. See do_IO() for more details. A devicedriver must never issue ESA/390 I/O commands itself, but must use theLinux/390 CDS interfaces instead.For long running I/O request to be canceled, the CDS layer provides thehalt_IO() function. Some devices require to initially issue a HALT SUBCHANNEL(HSCH) command without having pending I/O requests. This function is alsocovered by halt_IO().When done with a device, the device driver calls free_irq() to release itsownership for the device. During free_irq() processing the CDS layer alsodisables the device from presenting further interrupts - the device driverdoesn't need to assure it. The device will be reenabled for interrupts withthe next call to request_irq().get_dev_info_by_irq() / get_dev_info_by_devno() - Retrieve Device InformationDuring system startup - init_IRQ() processing - the generic I/O device supportchecks for the devices available. For all devices found it collects theSenseID information. For those devices supporting the command it also obtainsextended SenseID information.int get_dev_info_by_irq( int irq, dev_info_t *devinfo);int get_dev_info_by_devno( unsigned int irq, dev_info_t *devinfo);irq - defines the subchannel, status information is to be returned for.devno - device number.devinfo - pointer to a user buffer of type dev_info_t that should be filled with device specific information.typedef struct { unsigned int devno; /* device number */ unsigned int status; /* device status */ senseid_t sid_data; /* senseID data */} dev_info_t;devno - device number as configured in the IOCDS.status - device statussid_data - data obtained by a SenseID callPossible status values are :DEVSTAT_NOT_OPER - device was found not-operational. In this case the caller should disregard the sid_data buffer content.//// SenseID response buffer layout//typedef struct { /* common part */ unsigned char reserved; /* always 0x'FF' */ unsigned short cu_type; /* control unit type */ unsigned char cu_model; /* control unit model */ unsigned short dev_type; /* device type */ unsigned char dev_model; /* device model */ unsigned char unused; /* padding byte */ /* extended part */ ciw_t ciw[62]; /* variable # of CIWs */} senseid_t;The ESA/390 I/O architecture defines certain device specific I/O functions.The device returns the device specific command code together with the SenseIDdata in so called Command Information Words (CIW) :typedef struct _ciw { unsigned int et : 2; // entry type unsigned int reserved : 2; // reserved unsigned int ct : 4; // command type unsigned int cmd : 8; // command unsigned int count : 16; // count} ciw_t;Possible CIW entry types are :#define CIW_TYPE_RDC 0x0; // read configuration data#define CIW_TYPE_SII 0x1; // set interface identifier#define CIW_TYPE_RNI 0x2; // read node identifierThe device driver may use these commands as appropriate.The get_dev_info_by_irq() / get_dev_info_by_devno() functions return: 0 - successful completion-ENODEV - irq or devno don't specify a known subchannel or device number.-EINVAL - invalid devinfo value.Usage Notes :In order to scan for known devices a device driver should scan all irqs bycalling get_dev_info() until it returns -ENODEV as there aren't any moreavailable devices.If a device driver wants to request ownership for a specific device it mustcall request_irq() prior to be able to issue any I/O request for it, includingabove mentioned device dependent commands.Please see the "ESA/390 Common I/O-Commandss and Self Description" manual,with IBM form number SA22-7204 for more details on how to read the Sense-IDoutput, CIWs and device independent commands.get_irq_by_devno() / get_devno_by_irq() - Convert device identifiersWhile some device drivers act on the irq (subchannel) only, others take userdefined device configurations on device number base, according to the devicenumbers configured in the IOCDS. The following routines serve the purpose toconvert irq values into device numbers and vice versa.int get_irq_by_devno( unsigned int devno );unsigned int get_devno_by_irq( int irq );The functions return :the requested irq/devno values-1 if the requested conversion can't be accomplished.This could either be caused by irq/devno be outside the valid range( value > 0xffff or value < 0 ) or not identifying a known device.read_dev_chars() - Read Device CharacteristicsThis routine returns the characteristics for the device specified.The function is meant to be called without an irq handler be in place.However, the irq for the requested device must not be locked or this willcause a deadlock situation ! Further, the driver must assure that nobodyelse has claimed ownership for the requested irq yet or the owning devicedriver's internal accounting may be affected.In case of a registered interrupt handler, the interrupt handler must beable to properly react on interrupts related to the read_dev_chars() I/Ocommands. While the request is procesed synchronously, the device interrupthandler is called for final ending status. In case of error situations theinterrupt handler may recover appropriately. The device irq handler canrecognize the corresponding interrupts by the interruption parameter be0x00524443. If using the function with an existing device interrupt handlerin place, the irq must be locked prior to call read_dev_chars().The function may be called enabled or disabled.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -