Writing Device Drivers

Registering Device IDs

Drivers will typically initialize and register device IDs in the drivers attach(9E) handler. As mentioned above, the driver is responsible for registering a device ID which is persistent. As such, the driver may be required to handle both devices which can provide a unique ID directly (WWN), and devices where fabricated IDs are written to and read from stable storage.

Registering a Device-Supplied ID

If the device can supply the driver with an identifier that is unique, the driver can simply initialize the device ID with this identifier and register the ID with the Solaris DDI.

/*
 * The device provides a guaranteed unique identifier,
 * in this case a SCSI3-WWN.  The WWN for the device has been
 * stored in the devices soft state.
 */
if (ddi_devid_init(dip, DEVID_SCSI3_WWN, un->un_wwn_len, un->un_wwn,
    &un->un_devid) != DDI_SUCCESS)
        return (DDI_FAILURE);

(void) ddi_devid_register(dip, un->un_devid);

Registering a Fabricated ID

A driver may also register device IDs for devices which do not directly supply a unique ID. If the device is capable of storing and retrieving a small amount of data in a reserved area, the driver can create a fabricated device ID and write it to the reserved area.

/*
 * the device doesn't supply a unique ID, attempt to read
 * a fabricated ID from the devices reserved data.
 */

if (xxx_read_deviceid(un, &devid_buf) == XXX_OK) {
        if (ddi_devid_valid(devid_buf) == DDI_SUCCESS) {
                devid_sz = ddi_devi_sizeof(devid_buf);
                un->un_devid = kmem_alloc(devid_sz, KM_SLEEP);
                bcopy(devid_buf, un->un_devid, devid_sz);
                ddi_devid_register(dip, un->un_devid);
                return (XXX_OK);
        }
}

/*
 * we failed to read a valid device ID from the device
 * fabricate an ID, store it on the device, and register
 * it with the DDI
 */

if (ddi_devid_init(dip, DEVID_FAB, 0, NULL, &un->un_devid)
    == DDI_FAILURE) {
        return (XXX_FAILURE);
}

if (xxx_write_deviceid(un) != XXX_OK) {
        ddi_devid_free(un->un_devid);
        un->un_devid = NULL;
        return (XXX_FAILURE);
}

ddi_devid_register(dip, un->un_devid);
return (XXX_OK);