Writing Device Drivers

probe(9E)

SCSI target devices are not self-identifying, so target drivers must have a probe(9E) routine. This routine must determine whether the expected type of device is present and responding.

The general structure and return codes of the probe(9E) routine are the same as those of other device drivers. SCSI target drivers must use the scsi_probe(9F) routine in their probe(9E) entry point. scsi_probe(9F) sends a SCSI inquiry command to the device and returns a code indicating the result. If the SCSI inquiry command is successful, scsi_probe(9F) allocates a scsi_inquiry(9S) structure and fills it in with the device's inquiry data. Upon return from scsi_probe(9F), the sd_inq field of the scsi_device(9S) structure points to this scsi_inquiry(9S) structure.

Because probe(9E) must be stateless, the target driver must call scsi_unprobe(9F) before probe(9E) returns, even if scsi_probe(9F) fails.

Example 14-1 shows a typical probe(9E) routine. It retrieves its scsi_device(9S) structure from the private field of its dev_info structure. It also retrieves the device's SCSI target and logical unit numbers so that it can print them in messages. The probe(9E) routine then calls scsi_probe(9F) to verify that the expected device (a printer in this case) is present.

If scsi_probe(9F) succeeds, it has attached the device's SCSI inquiry data in a scsi_inquiry(9S) structure to the sd_inq field of the scsi_device(9S) structure. The driver can then determine if the device type is a printer (reported in the inq_dtype field). If it is, the type is reported with scsi_log(9F), using scsi_dname(9F) to convert the device type into a string.


Example 14-1 SCSI Target Driver probe(9E) Routine

static int
xxprobe(dev_info_t *dip)
{
    struct scsi_device *sdp;
    int rval, target, lun;
    /*
     * Get a pointer to the scsi_device(9S) structure
     */
    sdp = (struct scsi_device *)ddi_get_driver_private(dip);

    target = sdp->sd_address.a_target;
    lun = sdp->sd_address.a_lun;
    /*
     * Call scsi_probe(9F) to send the Inquiry command. It will
     * fill in the sd_inq field of the scsi_device structure.
     */
    switch (scsi_probe(sdp, NULL_FUNC)) {
    case SCSIPROBE_FAILURE:
    case SCSIPROBE_NORESP:
    case SCSIPROBE_NOMEM:
           /*
            * In these cases, device may be powered off,
            * in which case we may be able to successfully
            * probe it at some future time - referred to
            * as `deferred attach'.
            */
            rval = DDI_PROBE_PARTIAL;
            break;
    case SCSIPROBE_NONCCS:
    default:
            /*
             * Device isn't of the type we can deal with,
             * and/or it will never be usable.
             */
            rval = DDI_PROBE_FAILURE;
            break;
    case SCSIPROBE_EXISTS:
            /*
             * There is a device at the target/lun address. Check
             * inq_dtype to make sure that it is the right device
             * type. See scsi_inquiry(9S)for possible device types.
             */
            switch (sdp->sd_inq->inq_dtype) {
            case DTYPE_PRINTER:
                scsi_log(sdp, "xx", SCSI_DEBUG,
                   "found %s device at target%d, lun%d\n",
                    scsi_dname((int)sdp->sd_inq->inq_dtype),
                    target, lun);
                rval = DDI_PROBE_SUCCESS;
                break;
            case DTYPE_NOTPRESENT:
            default:
                rval = DDI_PROBE_FAILURE;
                break;     
            }    
    }
    scsi_unprobe(sdp);
    return (rval);
}

A more thorough probe(9E) routine could also check other fields of the scsi_inquiry(9S) structure as necessary to make sure that the device is of the type expected by a particular driver.