S/390 驱动模型接口

1. CCW 设备

所有可以通过 ccw 寻址的设备都被称为“CCW 设备”——即使它们实际上并非由 ccw 驱动。

所有 ccw 设备都是通过子通道(subchannel)访问的,这反映在 devices/ 下的结构中

devices/
   - system/
   - css0/
         - 0.0.0000/0.0.0815/
         - 0.0.0001/0.0.4711/
         - 0.0.0002/
         - 0.1.0000/0.1.1234/
         ...
         - defunct/

在此示例中,设备 0815 通过子通道集 0 中的子通道 0 访问,设备 4711 通过子通道集 0 中的子通道 1 访问,而子通道 2 是一个非 I/O 子通道。设备 1234 通过子通道集 1 中的子通道 0 访问。

名为“defunct”的子通道不代表系统上的任何真实子通道;它是一个伪子通道,当断开连接的 ccw 设备被在其原先子通道上变得可操作的另一个 ccw 设备取代时,这些断开连接的 ccw 设备会被移至此处。如果这些 ccw 设备在那个子通道上再次变得可操作,它们将被移回适当的子通道。

您应该通过其总线 ID(例如 0.0.4711)来寻址 ccw 设备;该设备可以在 bus/ccw/devices/ 下找到。

所有 ccw 设备都通过 sysfs 导出一些数据。

cutype

控制单元类型 / 型号。

devtype

设备类型 / 型号(如果适用)。

availability

可以是 ‘good’ 或 ‘boxed’;对于断开连接的设备,可以是 ‘no path’ 或 ‘no device’。

online

用于将设备设置为在线和离线的接口。在设备断开连接的特殊情况下(参见 1.2 下的 notify 函数),向 online 写入 0 将强制删除设备。

设备驱动程序可以添加条目以导出每个设备的数据和接口。

还有一些按子通道导出的数据(参见 bus/css/devices/ 下的内容)

chpids

设备通过哪些 chpid 连接。

pimpampom

已安装路径、可用路径和可操作路径的掩码。

可能还有其他附加数据,例如针对块设备的数据。

1.1 启动一个 ccw 设备

这分几个步骤完成。

  1. 每个驱动程序可以提供一个或多个可以指定参数的参数接口。这些接口也由驱动程序负责。

  2. 在执行完 a. 之后(如有必要),最后通过 ‘online’ 接口启动设备。

1.2 为 ccw 设备编写驱动程序

基本的 struct ccw_devicestruct ccw_driver 数据结构可以在 include/asm/ccwdev.h 下找到

struct ccw_device {
      spinlock_t *ccwlock;
      struct ccw_device_private *private;
      struct ccw_device_id id;

      struct ccw_driver *drv;
      struct device dev;
      int online;

      void (*handler) (struct ccw_device *dev, unsigned long intparm,
                       struct irb *irb);
};

struct ccw_driver {
      struct module *owner;
      struct ccw_device_id *ids;
      int (*probe) (struct ccw_device *);
      int (*remove) (struct ccw_device *);
      int (*set_online) (struct ccw_device *);
      int (*set_offline) (struct ccw_device *);
      int (*notify) (struct ccw_device *, int);
      struct device_driver driver;
      char *name;
};

‘private’ 字段仅包含内部 I/O 操作所需的数据,对设备驱动程序不可用。

每个驱动程序都应在 MODULE_DEVICE_TABLE 中声明它感兴趣的控制单元(CU)类型/型号和/或设备类型/型号。这些信息稍后可以在 struct ccw_device_id 字段中找到

struct ccw_device_id {
      __u16   match_flags;

      __u16   cu_type;
      __u16   dev_type;
      __u8    cu_model;
      __u8    dev_model;

      unsigned long driver_info;
};

ccw_driver 中的函数应按以下方式使用

probe

设备层会为驱动程序感兴趣的每个设备调用此函数。驱动程序应仅分配用于放入 dev->driver_data 的私有结构并创建属性(如果需要)。此外,应在此处设置中断处理程序(见下文)。

int (*probe) (struct ccw_device *cdev);
参数
cdev
  • 要探测的设备。

remove

当移除驱动程序、设备或模块时,设备层会调用此函数。驱动程序应在此处执行清理工作。

int (*remove) (struct ccw_device *cdev);
参数
cdev
  • 要移除的设备。

set_online

当通过 ‘online’ 属性激活设备时,公共 I/O 层会调用此函数。驱动程序应最终在此处设置并激活设备。

int (*set_online) (struct ccw_device *);
参数
cdev
  • 要激活的设备。公共层已验证该设备尚未处于在线状态。

set_offline: 当设备通过 ‘online’ 属性被停用时,公共 I/O 层会

调用此函数。驱动程序应关闭设备,但不要释放其私有数据。

int (*set_offline) (struct ccw_device *);
参数
cdev
  • 要停用的设备。公共层已

    验证该设备处于在线状态。

notify

当设备的某些状态发生变化时,公共 I/O 层会调用此函数。

发送给驱动程序的信号有

  • 在在线状态下,设备断开(CIO_GONE)或最后一条路径消失(CIO_NO_PATH)。驱动程序必须返回非 0 值(!0)来保留设备;对于返回值 0,设备将像往常一样被删除(如果没有注册 notify 函数也是如此)。如果驱动程序想保留该设备,它将被移入断开连接状态。

  • 在断开连接状态下,设备重新恢复操作(CIO_OPER)。公共 I/O 层对设备号和设备/控制单元(CU)执行一些完整性检查,以基本确定它是否仍然是同一个设备。如果不是,则移除旧设备并注册一个新设备。设备驱动程序通过 notify 函数的返回值来表明它是否想要找回该设备:!0 表示保留,0 表示让设备被移除并重新注册。

int (*notify) (struct ccw_device *, int);
参数
cdev
  • 状态发生改变的设备。

event
  • 发生的事件。这可以是 CIO_GONE、CIO_NO_PATH 或 CIO_OPER 之一。

struct ccw_device 的 handler 字段旨在设置为设备的中断处理程序。为了适应使用多个不同处理程序的驱动程序(例如多子通道设备),这是 ccw_device 的一个成员,而不是 ccw_driver 的。该处理程序在调用驱动程序之前的 set_online() 处理期间向公共层注册,并在调用驱动程序之后的 set_offline() 期间注销。此外,在注册之后/注销之前,会执行路径分组或解散路径组(如果适用)。

void (*handler) (struct ccw_device *dev, unsigned long intparm, struct irb *irb);
参数:dev - 调用此处理程序的设备
intparm - 允许设备驱动程序识别

中断所关联的 I/O,或者将该中断识别为非请求(unsolicited)中断的参数。

irb - 包含累积的

状态的中断响应块。

设备驱动程序从公共 ccw_device 层被调用,并且可以从 irb 参数中检索有关中断的信息。

1.3 ccwgroup 设备

ccwgroup 机制旨在处理由多个 ccw 设备组成的设备,例如 qeth 或 ctc。

ccw 驱动程序提供了一个 ‘group’ 属性。将 ccw 设备的总线 ID 写入此属性可以创建一个由这些 ccw 设备组成的 ccwgroup 设备(如果可能的话)。就像普通的 ccw 设备一样,这个 ccwgroup 设备可以被设置为在线或离线。

每个 ccwgroup 设备还提供了一个 ‘ungroup’ 属性以再次销毁该设备(仅在离线时)。这是一个通用的 ccwgroup 机制(驱动程序无需实现超出常规移除例程之外的任何内容)。

作为 ccwgroup 设备成员的 ccw 设备在其设备结构的 driver_data 中携带一个指向该 ccwgroup 设备的指针。驱动程序绝不能修改该字段——它应该使用 ccwgroup 设备的 driver_data 来存放其私有数据。

要实现一个 ccwgroup 驱动程序,请参考 include/asm/ccwgroup.h。请记住,大多数驱动程序需要同时实现 ccwgroup 驱动程序和 ccw 驱动程序。

2. 通道路径

与子通道一样,通道路径也会出现在通道子系统根目录(css0)下,被称为 ‘chp0.<chpid>’。它们没有驱动程序,也不属于任何总线。请注意,与 2.4 中的 /proc/chpids 不同,通道路径对象仅反映逻辑状态而不反映物理状态,因为由于缺乏机器支持,我们无法始终如一地追踪后者(无论如何我们也不需要了解它)。

status
  • 可以是 ‘online’ or ‘offline’。向其写入 ‘on’ 或 ‘off’ 会使 chpid 在逻辑上处于在线/离线状态。向处于在线状态的 chpid 写入 ‘on’ 会触发对其连接的所有设备的路径重新探测。这可用于强制内核重用用户已知在线但机器尚未为其创建机器检查的通道路径。

type
  • 通道路径的物理类型。

共享
  • 通道路径是否共享。

cmg
  • 通道测量组。

3. 系统设备

3.1 xpram

xpram 在 devices/system/ 下显示为 ‘xpram’。

3.2 cpus

对于每个 cpu,都会在 devices/system/cpu/ 下创建一个目录。每个 cpu 都有一个 ‘online’ 属性,其值可以为 0 或 1。