Go to main content

Writing Device Drivers for Oracle® Solaris 11.3

Exit Print View

Updated: March 2019
 
 

SR-IOV Driver Ioctls

The SR-IOV driver ioctls are used to identify the device specific parameters that can be configured by the administrator and to validate a specific configuration before it is applied. The following sections describe the ioctls data structures and the interfaces.

Data Structures

The following sections list the data structures that the PF driver should define and initialize before implementing the ioctls:

iov_param_ver_info Structure

The iov_param_ver_info structure is defined as follows:

#define IOV_IOCTL (('I' << 24) | ('O' << 16) | ('V' << 8))
#define IOV_GET_VER_INFO (IOV_IOCTL | 0)
#define IOV_GET_PARAM_INFO (IOV_IOCTL | 1)
#define IOV_VALIDATE_PARAM (IOV_IOCTL | 2)
#define IOV_PARAM_DESC_VERSION  1

The iov_param_ver_info structure contains the following fields:

typedef struct iov_param_ver_info {
uint32_t version; 
uint32_t num_params; 
} iov_param_ver_info_t;

where:

version

Version information

num_params

Number of parameters

iov_param_validate Structure

The iov_param_validate structure is defined as follows:

  #define IOV_IOCTL (('I' << 24) | ('O' << 16) | ('V' << 8))
  #define IOV_GET_VER_INFO (IOV_IOCTL | 0)
  #define IOV_GET_PARAM_INFO (IOV_IOCTL | 1)
  #define IOV_VALIDATE_PARAM  (IOV_IOCTL | 2)
  #define IOV_PARAM_DESC_VERSION  1

The iov_param_validate contains the following fields:

typedef struct iov_param_validate {
 	char pv_reason[MAX_REASON_LEN + 1];
 	int32_t pv_buflen;
 	/* encoded buffer containing params */
    char pv_buf[1];  /* size of buf is pv_buflen */          
} iov_param_validate_t;

where:

pv_reason

An ASCII string that explains the reason for failure if the ioctl call fails.

pv_buflen

Length of buffer pv_buf

pv_buf

Buffer containing the parameters

iov_param_desc Structure

The iov_param_desc structure is defined as follows:

	 #define IOV_IOCTL  (('I' << 24) | ('O' << 16) | ('V' << 8))
  #define IOV_GET_VER_INFO (IOV_IOCTL | 0)
  #define IOV_GET_PARAM_INFO (IOV_IOCTL | 1)
  #define IOV_VALIDATE_PARAM (IOV_IOCTL | 2)
  #define IOV_PARAM_DESC_VERSION  1

The structure iov_param_desc contains the following fields:

typedef struct iov_param_desc {
char pd_name[MAX_PARAM_NAME_SIZE];
char pd_desc[MAX_PARAM_DESC_SIZE];
int32_t pd_flag;   /* applicable for PF or VF or both */
int32_t pd_data_type; /* integer, string, plist */
/* Following 3 are applicable for integer data types */
uint64_t pd_default_value;
uint64_t pd_min64;	
uint64_t pd_max64;
char pd_default_string [MAX_PARAM_DEFAULT_STRING_SIZE];
} iov_param_desc_t; 

where:

pd_name

Used in the ldm (1M) command or the pci.conf file to assign a value to the parameter.

pd_desc

A brief description of the parameter.

pd_flag

Indicates if the parameter is applicable to only PF, only VF or applicable to both PF and VF.

pd_default_value

Value assigned by the driver if parameter is not specified in the ldm() command or pci.conf file.

pd_min64

Specifies the minimum range of values for the integer parameter

pd_max64

Specifies the maximum range of values for the integer parameter.

pd_default_string

Specifies the default string that will be used, if parameter is a string.

IOV_GET_VER_INFO Ioctl

SR-IOV device drivers that implement the IOV_GET_VER_INFO IOCTL() ioctl should set the version and the num_params fields in the iov_param_ver_info structure and return the values to the calling function. The calling function then uses the version and num_params parameters to determine the size of buffer required to get parameter descriptions using the IOV_GET_PARAM_INFO() ioctl call.

IOV_GET_PARAM_INFO Ioctl

    The general flow of control for a driver that calls the IOV_GET_PARAM_INFO() ioctl is as follows:

  1. Keep an array of iov_param_desc_t structures which contain description for each of the configurable params that are supported by the structure. See iov_param_desc Structure for the structure description.

  2. Copy out the array of iov_param_desc_t structures to the arg parameter. The fields in the iov_param_desc_t structure are static and can be defined at compile time.

    The number of elements in the array is the num_params value returned by the IOV_GET_VER_INFO() ioctl call. The size of the buffer is sizeof (iov_param_desc_t) * num_params

IOV_VALIDATE_PARAM Ioctl

    The general flow of control for a driver that calls the IOV_VALIDATE_PARAM() is as follows:

  1. Send the arg parameter to the pci_param_get_ioctl() interface and obtain a pointer to the pci_param_t structure.

  2. Write an explanatory string to the pv_reason array if param validation fails.

  3. Call the pci_get_plist() interface followed by the pci_plist_lookup() interface to obtain the device parameters.

  4. Lookup the vfs name-value pair in the PF plist to obtain the number of VFs to be configured for the validation of this configuration. The drivers should use integer data type of at least 16 bits to look up vfs name-value pair. Use the pciv_plist_getvf() interface to get the plist parameter for the VF devices.

  5. Validate the parameters without actually applying them to the device.

  6. Return 0 when a valid configuration is found.


Caution

Caution  - The parameters validated in the above procedure are not related to the current configuration of the device in any way. They need to be validated separately assuming they could be a future configuration. If not, the driver should return DDI_EINVAL to indicate improper configuration. The driver should also provide an explanatory string in the pv_reason field in the iov_param_validate structure when invalid configurations are found. This string informs the administrator why the configuration failed.


Sample Code for Driver Ioctls

enum ioc_reply
igb_ioctl(igb_t *igb, struct iocblk *iocp, mblk_t *mp)
{
		int rval = 0;
		iov_param_ver_info_t *iov_param_ver;
		iov_param_validate_t pvalidate;
		pci_param_t my_params;
		char reason[81];

if (mp->b_cont == NULL)
		return (IOC_INVAL);
if ((int)iocp->ioc_count < 0)
		return (IOC_INVAL);
switch (iocp->ioc_cmd) {
		case IOV_GET_PARAM_VER_INFO:
			if (iocp->ioc_count < sizeof (iov_param_ver_info_t))
				return (IOC_INVAL);
			iov_param_ver = (iov_param_ver_info_t *)(mp->b_cont->b_rptr);
			iov_param_ver->version = IOV_PARAM_DESC_VERSION;
			iov_param_ver->num_params = NUM_OF_PARAMS;
		return (IOC_REPLY);
		case IOV_GET_PARAM_INFO:
			if (iocp->ioc_count < sizeof (pci_list))
				return (IOC_INVAL);
			memcpy((caddr_t)(mp->b_cont->b_rptr), &pci_list,sizeof (pci_list));
			return (IOC_REPLY);
		case IOV_VALIDATE_PARAM:
			if (iocp->ioc_count <= 0)
				return (IOC_INVAL);
			strcpy(reason, "Failed to read params sent\n");
			rval = pci_param_get_ioctl(igb->dip,(uintptr_t)(mp->b_cont->b_rptr),
					 iocp->ioc_flag | FKIOCTL,&my_params );
			if (rval == 0) {
				rval = validate_params(igb->dip, my_params, reason);
			pci_param_free(my_params);
	}
if (rval) {
		memcpy(mp->b_cont->b_rptr, reason, sizeof (reason));
		iocp->ioc_count = sizeof (reason);
		return (IOC_REPLY);
}
iocp->ioc_count = 0;
return (IOC_REPLY);
iov_param_ver_info_t iov_param_ver;
iov_param_validate_t pvalidate;
pci_param_t	my_params;

switch (cmd) {
case IOV_GET_PARAM_VER_INFO:
		iov_param_ver.version = IOV_PARAM_DESC_VERSION;
		iov_param_ver.num_params = NUM_OF_PARAMS;
		if (ddi_copyout(&iov_param_ver, (caddr_t)arg,
			sizeof (iov_param_ver_info_t), mode) != DDI_SUCCESS)
		return (DEFAULT);
		return (0);
case IOV_GET_PARAM_INFO:
		if (ddi_copyout(&pci_list, (caddr_t)arg,param_list_size, mode) != DDI_SUCCESS)
		return (DEFAULT);
		return (0);
case IOV_VALIDATE_PARAM:
		strcpy(reason, "Failed to read params sent\n");
		rv = pci_param_get_ioctl(state->dip, arg, mode, &my_params);
		if (rv == 0)
			rv = validate_params(state->dip, my_params, reason); 
		else
			return (rv);
		pci_param_free(my_params);
	if (rv) {
		if (ddi_copyout(reason,iov_param_validate_t *)arg)->pv_reason,
			 sizeof (reason), mode) != DDI_SUCCESS)
		return (DEFAULT);
 return (rv);
	}
return (0);