Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
14.  SCSI Target Drivers Hardware Configuration File  Previous   Contents   Next 
   
 

Declarations and Data Structures

Target drivers must include the header file <sys/scsi/scsi.h>.

SCSI target drivers must use the following command to generate a binary module:

ld -r xx xx.o -N"misc/scsi"

scsi_device Structure

The host bus adapter driver allocates and initializes a scsi_device(9S) structure for the target driver before either the probe(9E) or attach(9E) routine is called. This structure stores information about each SCSI logical unit, including pointers to information areas that contain both generic and device-specific information. There is one scsi_device(9S) structure for each logical unit attached to the system. The target driver can retrieve a pointer to this structure by calling ddi_get_driver_private(9F).


Caution - Because the host bus adapter driver uses the private field in the target device's dev_info structure, target drivers must not use ddi_set_driver_private(9F).


The scsi_device(9S) structure contains the following fields:

struct scsi_device {
        struct scsi_address           sd_address;    /* opaque address */
        dev_info_t                    *sd_dev;       /* device node */
        kmutex_t                      sd_mutex;
        void                          *sd_reserved;
        struct scsi_inquiry           *sd_inq;
        struct scsi_extended_sense    *sd_sense;
        caddr_t                       sd_private;
};
sd_address

Data structure that is passed to the SCSI resource allocation routines.

sd_dev

Pointer to the target's dev_info structure.

sd_mutex

Mutex for use by the target driver. This is initialized by the host bus adapter driver and can be used by the target driver as a per-device mutex. Do not hold this mutex across a call to scsi_transport(9F) or scsi_poll(9F). See Chapter 3, Multithreading for more information on mutexes.

sd_inq

Pointer for the target device's SCSI inquiry data. The scsi_probe(9F) routine allocates a buffer, fills it in with inquiry data, and attaches it to this field.

sd_sense

Pointer to a buffer to contain SCSI request sense data from the device. The target driver must allocate and manage this buffer itself; see "attach() Entry Point (SCSI Target Drivers)".

sd_private

Pointer field for use by the target driver. It is commonly used to store a pointer to a private target driver state structure.

scsi_pkt Structure

The scsi_pkt structure contains the following fields:

struct scsi_pkt {
        opaque_t  pkt_ha_private;        /* private data for host adapter */
        struct scsi_address pkt_address; /* destination packet is for */
        opaque_t  pkt_private;           /* private data for target driver */
        void     (*pkt_comp)(struct scsi_pkt *); /* completion routine */
        uint_t   pkt_flags;              /* flags */
        int      pkt_time;               /* time allotted to complete command */
        uchar_t  *pkt_scbp;              /* pointer to status block */
        uchar_t  *pkt_cdbp;              /* pointer to command block */
        ssize_t  pkt_resid;              /* data bytes not transferred */
        uint_t   pkt_state;              /* state of command */
        uint_t   pkt_statistics;         /* statistics */
        uchar_t  pkt_reason;             /* reason completion called */
};
pkt_address

Target device's address set by scsi_init_pkt(9F).

pkt_private

Place to store private data for the target driver. It is commonly used to save the buf(9S) pointer for the command.

pkt_comp

Address of the completion routine. The host bus adapter driver calls this routine when it has transported the command. This does not mean that the command succeeded; the target might have been busy or might not have responded before the time-out time elapsed (see the description for pkt_time field). The target driver must supply a valid value in this field, though it can be NULL if the driver does not want to be notified.


Note - There are two different SCSI callback routines. The pkt_comp field identifies a completion callback routine, which is called when the host bus adapter completes its processing. There is also a resource callback routine, called when currently unavailable resources are likely to be available (as in scsi_init_pkt(9F)).


pkt_flags

Provides additional control information, for example, to transport the command without disconnect privileges (FLAG_NODISCON) or to disable callbacks (FLAG_NOINTR). See the scsi_pkt(9S) man page for details.

pkt_time

Time-out value (in seconds). If the command is not completed within this time, the host bus adapter calls the completion routine with pkt_reason set to CMD_TIMEOUT. The target driver should set this field to longer than the maximum time the command might take. If the timeout is zero, no timeout is requested. Timeout starts when the command is transmitted on the SCSI bus.

pkt_scbp

Pointer to the SCSI status completion block; this is filled in by the host bus adapter driver.

pkt_cdbp

Pointer to the SCSI command descriptor block, the actual command to be sent to the target device. The host bus adapter driver does not interpret this field. The target driver must fill it in with a command that the target device can process.

pkt_resid

Residual of the operation. When allocating DMA resources for a command scsi_init_pkt(9F), pkt_resid indicates the number of bytes for which DMA resources could not be allocated because of DMA hardware scatter-gather or other device limitations. After command transport, pkt_resid indicates the number of data bytes not transferred; this is filled in by the host bus adapter driver before the completion routine is called.

pkt_state

Indicates the state of the command. The host bus adapter driver fills in this field as the command progresses. One bit is set in this field for each of the five following command states:

  • STATE_GOT_BUS - Acquired the bus

  • STATE_GOT_TARGET - Selected the target

  • STATE_SENT_CMD - Sent the command

  • STATE_XFERRED_DATA - Transferred data (if appropriate)

  • STATE_GOT_STATUS - Received status from the device

pkt_statistics

Contains transport-related statistics set by the host bus adapter driver.

pkt_reason

Gives the reason the completion routine was called. The main function of the completion routine is to decode this field and take the appropriate action. If the command completed--in other words, if there were no transport errors--this field is set to CMD_CMPLT; other values in this field indicate an error. After a command is completed, the target driver should examine the pkt_scbp field for a check condition status. See the scsi_pkt(9S) man page for more information.

Autoconfiguration for SCSI Target Drivers

SCSI target drivers must implement the standard autoconfiguration routines _init(9E), _fini(9E), and _info(9E). See "Loadable Driver Interfaces" for more information.

probe(9E), attach(9E), detach(9E), and getinfo(9E) are also required, but they must perform SCSI (and SCSA) specific processing.

probe() Entry Point (SCSI Target Drivers)

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);
}

 
 
 
  Previous   Contents   Next