Data structures are the mechanism used to pass information between peripheral device drivers and the CAM subsystem. This chapter describes the CAM data structures that peripheral device drivers use. They are defined in the file /usr/sys/include/io/cam/cam.h. This chapter discusses the following:
Other chapters reference these structures. You can read this chapter now to become familiar with the structures, or you can refer to it when you encounter references to the structures in other chapters.
The CAM control block (CCB) data structures let the device driver writer specify the action to be performed by the XPT and SIM. The CCBs are allocated by calling the xpt_ccb_alloc routine. Table 5-1 contains the name of each CCB data structure and a brief description.
CCB Name | Description |
CCB_SCSIIO | Requests SCSI I/O. |
CCB_GETDEV | Gets device type. |
CCB_PATHINQ | Sends a path inquiry. |
CCB_RELSIM | Releases SIM queue. |
CCB_SETASYNC | Sets asynchronous callback. |
CCB_SETDEV | Sets device type. |
CCB_ABORT | Aborts XPT request. |
CCB_RESETBUS | Resets SCSI bus. |
CCB_RESETDEV | Resets SCSI device. |
CCB_TERMIO | Terminates I/O process request. |
All CCBs contain a CCB_HEADER structure. Peripheral device driver writers need to understand the CCB_HEADER data structure, which is discussed in the section that follows.
SCSI/CAM peripheral device driver writers allocate a CCB structure by calling the xpt_ccb_alloc routine. The CCB_HEADER structure is common to all CCBs and is the first structure filled in. It contains the following members:
typedef struct ccb_header { struct ccb_header *my_addr; /* The address of this CCB */ u_short cam_ccb_len; /* Length of the entire CCB */ u_char cam_func_code; /* XPT function code */ u_char cam_status; /* Returned CAM subsystem */ /* status */ u_char cam_path_id; /* Path ID for the request */ u_char cam_target_id; /* Target device ID */ u_char cam_target_lun; /* Target LUN number */ u_long cam_flags; /* Flags for operation of */ /* the subsystem */ } CCB_HEADER;
The my_addr member is set to a pointer to the virtual address of the starting address of the CCB. The xpt_ccb_alloc routine automatically fills it in.
The cam_ccb_len member is set to the length (in bytes) of this specific CCB type. The ccmn_get_ccb routine fills in this member. The length includes the my_addr and cam_ccb_len members.
The cam_func_code member lets device driver writers specify the CCB type XPT/SIM functions. Device driver writers can set this member to one of the function codes listed in Table 5-2. They are defined in the file /usr/sys/include/io/cam/cam.h.
Function Code | Meaning |
XPT_NOOP | Do not execute anything in the XPT/SIM. |
XPT_SCSI_IO | Execute the requested SCSI I/O. You specify the details of the SCSI I/O by setting the appropriate members of the CCB_SCSIIO structure. |
XPT_GDEV_TYPE | Get the device type information. You obtain this information by referencing the CCB_GETDEV structure. |
XPT_PATH_INQ | Get the path inquiry information. You obtain this information by referencing the CCB_PATHINQ structure. |
XPT_REL_SIMQ | Release the SIM queue that is frozen. |
XPT_ASYNC_CB | Set the asynchronous callback parameters. You obtain asynchronous callback information from the CCB_SETASYNC structure. |
XPT_SDEV_TYPE | Set the device type information. You obtain the device type information from the CCB_SETDEV structure. |
XPT_ABORT | Abort the specified CCB. You specify the abort to the CCB by setting the appropriate member of the CCB_ABORT structure. |
XPT_RESET_BUS | Reset the SCSI bus. |
XPT_RESET_DEV | Reset the SCSI device. |
XPT_TERM_IO | Terminate the I/O process. You specify the CCB process to terminate by setting the appropriate member of the CCB_TERMIO structure. |
The cam_status member is the action or event that occurred during this CCB request. The cam_status member is set by the XPT/SIM after the specified function has completed. A CAM_REQ_INPROG status indicates that either the function is still executing or is still in the queue. The XPT/SIM can set this member to one of the CAM status codes listed in Table 5-3. They are defined in the file /usr/sys/include/io/cam/cam.h.
CAM Status Code | Meaning |
CAM_REQ_INPROG | A CCB request is in progress. |
CAM_REQ_CMP | A CCB request was completed without errors. |
CAM_REQ_ABORTED | A CCB request was aborted by the host processor. |
CAM_REQ_UA_ABORT | The SIM was not able to abort the specified CCB. |
CAM_REQ_CMP_ERR | The specified CCB request was completed with an error. |
CAM_BUSY | The CAM subsystem is busy. The CCB returns to the caller; the request must be resubmitted. |
CAM_REQ_INVALID | The specified CCB request is not valid. |
CAM_PATH_INVALID | The path ID specified in the cam_path_id member of the CCB_HEADER structure is not valid. |
CAM_DEV_NOT_THERE | The specified SCSI device is not installed at this location. |
CAM_UA_TERMIO | The CAM subsystem was unable to terminate the specified CCB I/O request. |
CAM_SEL_TIMEOUT | A target-selection timeout occurred. |
CAM_CMD_TIMEOUT | A command timeout occurred. |
CAM_MSG_REJECT_REC | A message rejection was received by the SIM. |
CAM_SCSI_BUS_RESET | The SCSI bus-reset was issued by the SIM or was seen on the bus by the SIM. |
CAM_UNCOR_PARITY | An uncorrectable parity error occurred. |
CAM_AUTOSENSE_FAIL | The autosense request-sense command failed. |
CAM_NO_HBA | No HBA was detected. |
CAM_DATA_RUN_ERR | A data overflow or underflow error occurred. |
CAM_UNEXP_BUSFREE | An unexpected bus free was detected. |
CAM_SEQUENCE_FAIL | A target bus phase-sequence failure occurred. |
CAM_CCB_LEN_ERR | The CCB length specified in the cam_ccb_len member of the CCB_HEADER structure is incorrect. |
CAM_PROVIDE_FAIL | The requested capability could not be provided. |
CAM_BDR_SENT | A SCSI BDR message was sent to the target. |
CAM_REQ_TERMIO | The CCB request was terminated by the host. |
CAM_LUN_INVALID | The LUN supplied is invalid. |
CAM_TID_INVALID | The target ID supplied is invalid. |
CAM_FUNC_NOTAVAIL | The requested function is not available. |
CAM_NO_NEXUS | A nexus has not been established. |
CAM_IID_INVALID | The initiator ID is invalid. |
CAM_CDB_RECVD | The SCSI CDB has been received. |
CAM_SCSI_BUSY | The SCSI bus is busy. |
CAM_SIM_QFRZN | The SIM queue is frozen. |
CAM_AUTOSNS_VALID | Autosense data is valid for the target. |
CAM_STATUS_MASK | The mask bits are only for the status. |
Peripheral device drivers make SCSI device action requests through the following data structures:
A peripheral driver indicates to the XPT/SIM that it wants to make a SCSI device action request by setting the cam_func_code member of the CCB_HEADER structure to the constant XPT_SCSI_IO. The peripheral driver writer then uses the CCB_SCSIIO structure to specify the requests.
The CCB_SCSIIO structure is defined as follows:
typedef struct { CCB_HEADER cam_ch; /* Header information fields */ u_char *cam_pdrv_ptr; /* Ptr to the Peripheral driver */ /* working set */ CCB_HEADER *cam_next_ccb; /* Ptr to the next CCB for action */ u_char *cam_req_map; /* Ptr for mapping info on the Req. */ void (*cam_cbfcnp)(); /* Callback on completion function */ u_char *cam_data_ptr; /* Pointer to the data buf/SG list */ u_long cam_dxfer_len; /* Data xfer length */ u_char *cam_sense_ptr; /* Pointer to the sense data buffer */ u_char cam_sense_len; /* Num of bytes in the Autosense buf */ u_char cam_cdb_len; /* Number of bytes for the CDB */ u_short cam_sglist_cnt; /* Num of scatter/gather list entries */ u_long cam_sort; /* Value used by the SIM to sort on */ cam_scsi_status /* Returned SCSI device status */ cam_sense_resid /* Autosense residual length: */ /* two's complement */ cam_osd_rsvdi[2] /* OSD reserved field for alignment */ long cam_resid; /* Transfer residual length: */ /* two's complement */ CDB_UN cam_cdb_io; /* Union for CDB bytes/pointer */ u_long cam_timeout; /* Timeout value */ u_char *cam_msg_ptr; /* Pointer to the message buffer */ u_short cam_msgb_len; /* Num of bytes in the message buf */ u_short cam_vu_flags; /* Vendor unique flags */ u_char cam_tag_action; /* What to do for tag queuing */ u_char cam_iorsvd0[3]; /* Reserved field, for alignment */ u_char cam_sim_priv[ SIM_PRIV ]; /* SIM private data area */ } CCB_SCSIIO;
The CDB_UN structure is defined as follows:
typedef union { u_char *cam_cdb_ptr; /* Pointer to the CDB bytes */ /* to send */ u_char cam_cdb_bytes[ IOCDBLEN ]; /* Area for the inline CDB *? /* to send */ } CDB_UN;
The control CCB structures allow the driver writer to specify such tasks as resetting the SCSI bus, terminating an I/O process request, and so forth. This section discusses the following control structures:
Device driver writers use the CCB_RELSIM structure to release the SIM's internal CCB queue. The CCB_RELSIM structure is defined as follows:
typedef struct { CCB_HEADER cam_ch; /* Header information fields */ } CCB_RELSIM;
SCSI/CAM peripheral device driver writers use the CCB_SETASYNC structure to set the asynchronous callback for notification of the following events when they occur:
The CCB_SETASYNC structure is defined as follows:
typedef struct { CCB_HEADER cam_ch; /* Header information fields */ u_long cam_async_flags; /* Event enables for Callback response */ void (*cam_async_func)(); /* Async Callback function address */ u_char *pdrv_buf; /* Buffer set aside by the */ /* peripheral driver */ u_char pdrv_buf_len; /* The size of the buffer */ } CCB_SETASYNC;
Device driver writers use the CCB_ABORT structure to abort a CCB that is on the SIM queue. The CCB_ABORT structure is defined as follows:
typedef struct { CCB_HEADER cam_ch; /* Header information fields */ CCB_HEADER *cam_abort_ch; /* Pointer to the CCB to abort */ } CCB_ABORT;
Device driver writers use the CCB_RESETBUS structure to reset the SCSI bus. The CCB_RESETBUS structure is defined as follows:
typedef struct { CCB_HEADER cam_ch; /* Header information fields */ } CCB_RESETBUS;
Device driver writers use the CCB_RESETDEV structure to reset a single SCSI device. The CCB_RESETDEV structure is defined as follows:
typedef struct { CCB_HEADER cam_ch; /* Header information fields */ } CCB_RESETDEV;
Device driver writers use the CCB_TERMIO structure to terminate an I/O process request. The CCB_TERMIO structure is defined as follows:
typedef struct { CCB_HEADER cam_ch; /* Header information fields */ CCB_HEADER *cam_termio_ch; /* Pointer to the CCB to terminate */ } CCB_TERMIO;
The configuration CCB structures let the driver writer obtain information such as the device type, version number for the SIM/HBA, and vendor IDs. The following configuration CCBs are described in this section:
Device driver writers use the CCB_GETDEV structure to obtain a device type and inquiry information. The CCB_GETDEV structure is defined as follows:
typedef struct { CCB_HEADER cam_ch; /* Header information fields */ u_char cam_pd_type; /* Peripheral device type from the TLUN */ char *cam_inq_data; /* Ptr to the inquiry data space */ } CCB_GETDEV;
Device driver writers use the CCB_SETDEV structure to set the device type. The CCB_SETDEV structure is defined as follows:
typedef struct { CCB_HEADER cam_ch; /* Header information fields */ u_char cam_dev_type; /* Value for the dev type field in EDT */ } CCB_SETDEV;
Device driver writers use the CCB_PATHINQ structure to obtain SIM information such as supported features and version numbers. The CCB_PATHINQ structure is defined as follows:
typedef struct { CCB_HEADER cam_ch; /* Header information fields */ u_char cam_version_num; /* Version number for the SIM/HBA */ u_char cam_hba_inquiry; /* Mimic of INQ byte 7 for the HBA */ u_char cam_target_sprt; /* Flags for target mode support */ u_char cam_hba_misc; /* Misc HBA feature flags */ u_char cam_vuhba_flags[ VUHBA ]; /* Vendor unique capabilities */ u_long cam_sim_priv; /* Size of SIM private data area */ u_long cam_async_flags; /* Event cap. for Async Callback */ u_char cam_hpath_id; /* Highest path ID in subsystem */ u_char cam_initiator_id; /* ID of the HBA on the SCSI bus */ char cam_sim_vid[ SIM_ID ]; /* Vendor ID of the SIM */ char cam_hba_vid[ HBA_ID ]; /* Vendor ID of the HBA */ u_char *cam_osd_usage; /* Ptr for the OSD specific area */ } CCB_PATHINQ;