JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Writing Device Drivers
search filter icon
search icon

Document Information


Part I Designing Device Drivers for the Solaris Platform

1.  Overview of Solaris Device Drivers

2.  Solaris Kernel and Device Tree

3.  Multithreading

4.  Properties

5.  Managing Events and Queueing Tasks

6.  Driver Autoconfiguration

7.  Device Access: Programmed I/O

8.  Interrupt Handlers

9.  Direct Memory Access (DMA)

10.  Mapping Device and Kernel Memory

11.  Device Context Management

12.  Power Management

13.  Hardening Solaris Drivers

14.  Layered Driver Interface (LDI)

Part II Designing Specific Kinds of Device Drivers

15.  Drivers for Character Devices

16.  Drivers for Block Devices

Block Driver Structure Overview

File I/O

Block Device Autoconfiguration

Controlling Device Access

open() Entry Point (Block Drivers)

close() Entry Point (Block Drivers)

strategy() Entry Point

buf Structure

bp_mapin Structure

Synchronous Data Transfers (Block Drivers)

Asynchronous Data Transfers (Block Drivers)

Checking for Invalid buf Requests

Enqueuing the Request

Starting the First Transfer

Handling the Interrupting Device

dump() and print() Entry Points

dump() Entry Point (Block Drivers)

print() Entry Point (Block Drivers)

Disk Device Drivers

Disk ioctls

Disk Performance

17.  SCSI Target Drivers

18.  SCSI Host Bus Adapter Drivers

19.  Drivers for Network Devices

20.  USB Drivers

Part III Building a Device Driver

21.  Compiling, Loading, Packaging, and Testing Drivers

22.  Debugging, Testing, and Tuning Device Drivers

23.  Recommended Coding Practices

Part IV Appendixes

A.  Hardware Overview

B.  Summary of Solaris DDI/DKI Services

C.  Making a Device Driver 64-Bit Ready

D.  Console Frame Buffer Drivers


Block Device Autoconfiguration

attach(9E) should perform the common initialization tasks for each instance of a device:

Block device drivers create minor nodes of type S_IFBLK. As a result, a block special file that represents the node appears in the /devices hierarchy.

Logical device names for block devices appear in the /dev/dsk directory, and consist of a controller number, bus-address number, disk number, and slice number. These names are created by the devfsadm(1M) program if the node type is set to DDI_NT_BLOCK or DDI_NT_BLOCK_CHAN. DDI_NT_BLOCK_CHAN should be specified if the device communicates on a channel, that is, a bus with an additional level of addressability. SCSI disks are a good example. DDI_NT_BLOCK_CHAN causes a bus-address field (tN) to appear in the logical name. DDI_NT_BLOCK should be used for most other devices.

A minor device refers to a partition on the disk. For each minor device, the driver must create an nblocks or Nblocks property. This integer property gives the number of blocks supported by the minor device expressed in units of DEV_BSIZE, that is, 512 bytes. The file system uses the nblocks and Nblocks properties to determine device limits. Nblocks is the 64-bit version of nblocks. Nblocks should be used with storage devices that can hold over 1 Tbyte of storage per disk. See Device Properties for more information.

Example 16-1 shows a typical attach(9E) entry point with emphasis on creating the device's minor node and the Nblocks property. Note that because this example uses Nblocks and not nblocks, ddi_prop_update_int64(9F) is called instead of ddi_prop_update_int(9F).

As a side note, this example shows the use of makedevice(9F) to create a device number for ddi_prop_update_int64(). The makedevice function makes use of ddi_driver_major(9F), which generates a major number from a pointer to a dev_info_t structure. Using ddi_driver_major() is similar to using getmajor(9F), which gets a dev_t structure pointer.

Example 16-1 Block Driver attach() Routine

static int
xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
     int instance = ddi_get_instance(dip);
     switch (cmd) {
       case DDI_ATTACH:
        * allocate a state structure and initialize it
        * map the devices registers
        * add the device driver's interrupt handler(s)
        * initialize any mutexes and condition variables
        * read label information if the device is a disk
        * create power manageable components
        * Create the device minor node. Note that the node_type
        * argument is set to DDI_NT_BLOCK.
       if (ddi_create_minor_node(dip, "minor_name", S_IFBLK,
          instance, DDI_NT_BLOCK, 0) == DDI_FAILURE) {
          /* free resources allocated so far */
          /* Remove any previously allocated minor nodes */
          ddi_remove_minor_node(dip, NULL);
          return (DDI_FAILURE);
        * Create driver properties like "Nblocks". If the device
        * is a disk, the Nblocks property is usually calculated from
        * information in the disk label.  Use "Nblocks" instead of
        * "nblocks" to ensure the property works for large disks.
       xsp->Nblocks = size;
       /* size is the size of the device in 512 byte blocks */
       maj_number = ddi_driver_major(dip);
       if (ddi_prop_update_int64(makedevice(maj_number, instance), dip, 
          "Nblocks", xsp->Nblocks) != DDI_PROP_SUCCESS) {
          cmn_err(CE_CONT, "%s: cannot create Nblocks property\n",
         /* free resources allocated so far */
         return (DDI_FAILURE);
       xsp->open = 0;
       xsp->nlayered = 0;
       /* ... */
       return (DDI_SUCCESS);

    case DDI_RESUME:
       /* For information, see Chapter 12, "Power Management," in this book. */
          return (DDI_FAILURE);