linux/drivers/scsi/mpi3mr/mpi3mr_app.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Driver for Broadcom MPI3 Storage Controllers
 *
 * Copyright (C) 2017-2023 Broadcom Inc.
 *  (mailto: [email protected])
 *
 */

#include "mpi3mr.h"
#include <linux/bsg-lib.h>
#include <uapi/scsi/scsi_bsg_mpi3mr.h>

/**
 * mpi3mr_alloc_trace_buffer:	Allocate trace buffer
 * @mrioc: Adapter instance reference
 * @trace_size: Trace buffer size
 *
 * Allocate trace buffer
 * Return: 0 on success, non-zero on failure.
 */
static int mpi3mr_alloc_trace_buffer(struct mpi3mr_ioc *mrioc, u32 trace_size)
{}

/**
 * mpi3mr_alloc_diag_bufs - Allocate memory for diag buffers
 * @mrioc: Adapter instance reference
 *
 * This functions checks whether the driver defined buffer sizes
 * are greater than IOCFacts provided controller local buffer
 * sizes and if the driver defined sizes are more then the
 * driver allocates the specific buffer by reading driver page1
 *
 * Return: Nothing.
 */
void mpi3mr_alloc_diag_bufs(struct mpi3mr_ioc *mrioc)
{}

/**
 * mpi3mr_issue_diag_buf_post - Send diag buffer post req
 * @mrioc: Adapter instance reference
 * @diag_buffer: Diagnostic buffer descriptor
 *
 * Issue diagnostic buffer post MPI request through admin queue
 * and wait for the completion of it or time out.
 *
 * Return: 0 on success, non-zero on failures.
 */
int mpi3mr_issue_diag_buf_post(struct mpi3mr_ioc *mrioc,
	struct diag_buffer_desc *diag_buffer)
{}

/**
 * mpi3mr_post_diag_bufs - Post diag buffers to the controller
 * @mrioc: Adapter instance reference
 *
 * This function calls helper function to post both trace and
 * firmware buffers to the controller.
 *
 * Return: None
 */
int mpi3mr_post_diag_bufs(struct mpi3mr_ioc *mrioc)
{}

/**
 * mpi3mr_issue_diag_buf_release - Send diag buffer release req
 * @mrioc: Adapter instance reference
 * @diag_buffer: Diagnostic buffer descriptor
 *
 * Issue diagnostic buffer manage MPI request with release
 * action request through admin queue and wait for the
 * completion of it or time out.
 *
 * Return: 0 on success, non-zero on failures.
 */
int mpi3mr_issue_diag_buf_release(struct mpi3mr_ioc *mrioc,
	struct diag_buffer_desc *diag_buffer)
{}

/**
 * mpi3mr_process_trigger - Generic HDB Trigger handler
 * @mrioc: Adapter instance reference
 * @trigger_type: Trigger type
 * @trigger_data: Trigger data
 * @trigger_flags: Trigger flags
 *
 * This function checks validity of HDB, triggers and based on
 * trigger information, creates an event to be processed in the
 * firmware event worker thread .
 *
 * This function should be called with trigger spinlock held
 *
 * Return: Nothing
 */
static void mpi3mr_process_trigger(struct mpi3mr_ioc *mrioc, u8 trigger_type,
	union mpi3mr_trigger_data *trigger_data, u8 trigger_flags)
{}

/**
 * mpi3mr_global_trigger - Global HDB trigger handler
 * @mrioc: Adapter instance reference
 * @trigger_data: Trigger data
 *
 * This function checks whether the given global trigger is
 * enabled in the driver page 2 and if so calls generic trigger
 * handler to queue event for HDB release.
 *
 * Return: Nothing
 */
void mpi3mr_global_trigger(struct mpi3mr_ioc *mrioc, u64 trigger_data)
{}

/**
 * mpi3mr_scsisense_trigger - SCSI sense HDB trigger handler
 * @mrioc: Adapter instance reference
 * @sensekey: Sense Key
 * @asc: Additional Sense Code
 * @ascq: Additional Sense Code Qualifier
 *
 * This function compares SCSI sense trigger values with driver
 * page 2 values and calls generic trigger handler to release
 * HDBs if match found
 *
 * Return: Nothing
 */
void mpi3mr_scsisense_trigger(struct mpi3mr_ioc *mrioc, u8 sensekey, u8 asc,
	u8 ascq)
{}

/**
 * mpi3mr_event_trigger - MPI event HDB trigger handler
 * @mrioc: Adapter instance reference
 * @event: MPI Event
 *
 * This function compares event trigger values with driver page
 * 2 values and calls generic trigger handler to release
 * HDBs if match found.
 *
 * Return: Nothing
 */
void mpi3mr_event_trigger(struct mpi3mr_ioc *mrioc, u8 event)
{}

/**
 * mpi3mr_reply_trigger - MPI Reply HDB trigger handler
 * @mrioc: Adapter instance reference
 * @ioc_status: Masked value of IOC Status from MPI Reply
 * @ioc_loginfo: IOC Log Info from MPI Reply
 *
 * This function compares IOC status and IOC log info trigger
 * values with driver page 2 values and calls generic trigger
 * handler to release HDBs if match found.
 *
 * Return: Nothing
 */
void mpi3mr_reply_trigger(struct mpi3mr_ioc *mrioc, u16 ioc_status,
	u32 ioc_loginfo)
{}

/**
 * mpi3mr_get_num_trigger - Gets number of HDB triggers
 * @mrioc: Adapter instance reference
 * @num_triggers: Number of triggers
 * @page_action: Page action
 *
 * This function reads number of triggers by reading driver page
 * 2
 *
 * Return: 0 on success and proper error codes on failure
 */
static int mpi3mr_get_num_trigger(struct mpi3mr_ioc *mrioc, u8 *num_triggers,
	u8 page_action)
{}

/**
 * mpi3mr_refresh_trigger - Handler for Refresh trigger BSG
 * @mrioc: Adapter instance reference
 * @page_action: Page action
 *
 * This function caches the driver page 2 in the driver's memory
 * by reading driver page 2 from the controller for a given page
 * type and updates the HDB trigger values
 *
 * Return: 0 on success and proper error codes on failure
 */
int mpi3mr_refresh_trigger(struct mpi3mr_ioc *mrioc, u8 page_action)
{}

/**
 * mpi3mr_release_diag_bufs - Release diag buffers
 * @mrioc: Adapter instance reference
 * @skip_rel_action: Skip release action and set buffer state
 *
 * This function calls helper function to release both trace and
 * firmware buffers from the controller.
 *
 * Return: None
 */
void mpi3mr_release_diag_bufs(struct mpi3mr_ioc *mrioc, u8 skip_rel_action)
{}

/**
 * mpi3mr_set_trigger_data_in_hdb - Updates HDB trigger type and
 * trigger data
 *
 * @hdb: HDB pointer
 * @type: Trigger type
 * @data: Trigger data
 * @force: Trigger overwrite flag
 * @trigger_data: Pointer to trigger data information
 *
 * Updates trigger type and trigger data based on parameter
 * passed to this function
 *
 * Return: Nothing
 */
void mpi3mr_set_trigger_data_in_hdb(struct diag_buffer_desc *hdb,
	u8 type, union mpi3mr_trigger_data *trigger_data, bool force)
{}

/**
 * mpi3mr_set_trigger_data_in_all_hdb - Updates HDB trigger type
 * and trigger data for all HDB
 *
 * @mrioc: Adapter instance reference
 * @type: Trigger type
 * @data: Trigger data
 * @force: Trigger overwrite flag
 * @trigger_data: Pointer to trigger data information
 *
 * Updates trigger type and trigger data based on parameter
 * passed to this function
 *
 * Return: Nothing
 */
void mpi3mr_set_trigger_data_in_all_hdb(struct mpi3mr_ioc *mrioc,
	u8 type, union mpi3mr_trigger_data *trigger_data, bool force)
{}

/**
 * mpi3mr_hdbstatuschg_evt_th - HDB status change evt tophalf
 * @mrioc: Adapter instance reference
 * @event_reply: event data
 *
 * Modifies the status of the applicable diag buffer descriptors
 *
 * Return: Nothing
 */
void mpi3mr_hdbstatuschg_evt_th(struct mpi3mr_ioc *mrioc,
	struct mpi3_event_notification_reply *event_reply)
{}

/**
 * mpi3mr_diag_buffer_for_type - returns buffer desc for type
 * @mrioc: Adapter instance reference
 * @buf_type: Diagnostic buffer type
 *
 * Identifies matching diag descriptor from mrioc for given diag
 * buffer type.
 *
 * Return: diag buffer descriptor on success, NULL on failures.
 */

struct diag_buffer_desc *
mpi3mr_diag_buffer_for_type(struct mpi3mr_ioc *mrioc, u8 buf_type)
{}

/**
 * mpi3mr_bsg_pel_abort - sends PEL abort request
 * @mrioc: Adapter instance reference
 *
 * This function sends PEL abort request to the firmware through
 * admin request queue.
 *
 * Return: 0 on success, -1 on failure
 */
static int mpi3mr_bsg_pel_abort(struct mpi3mr_ioc *mrioc)
{}
/**
 * mpi3mr_bsg_verify_adapter - verify adapter number is valid
 * @ioc_number: Adapter number
 *
 * This function returns the adapter instance pointer of given
 * adapter number. If adapter number does not match with the
 * driver's adapter list, driver returns NULL.
 *
 * Return: adapter instance reference
 */
static struct mpi3mr_ioc *mpi3mr_bsg_verify_adapter(int ioc_number)
{}

/**
 * mpi3mr_bsg_refresh_hdb_triggers - Refresh HDB trigger data
 * @mrioc: Adapter instance reference
 * @job: BSG Job pointer
 *
 * This function reads the controller trigger config page as
 * defined by the input page type and refreshes the driver's
 * local trigger information structures with the controller's
 * config page data.
 *
 * Return: 0 on success and proper error codes on failure
 */
static long
mpi3mr_bsg_refresh_hdb_triggers(struct mpi3mr_ioc *mrioc,
				struct bsg_job *job)
{}

/**
 * mpi3mr_bsg_upload_hdb - Upload a specific HDB to user space
 * @mrioc: Adapter instance reference
 * @job: BSG Job pointer
 *
 * Return: 0 on success and proper error codes on failure
 */
static long mpi3mr_bsg_upload_hdb(struct mpi3mr_ioc *mrioc,
				  struct bsg_job *job)
{}

/**
 * mpi3mr_bsg_repost_hdb - Re-post HDB
 * @mrioc: Adapter instance reference
 * @job: BSG job pointer
 *
 * This function retrieves the HDB descriptor corresponding to a
 * given buffer type and if the HDB is in released status then
 * posts the HDB with the firmware.
 *
 * Return: 0 on success and proper error codes on failure
 */
static long mpi3mr_bsg_repost_hdb(struct mpi3mr_ioc *mrioc,
				  struct bsg_job *job)
{}

/**
 * mpi3mr_bsg_query_hdb - Handler for query HDB command
 * @mrioc: Adapter instance reference
 * @job: BSG job pointer
 *
 * This function prepares and copies the host diagnostic buffer
 * entries to the user buffer.
 *
 * Return: 0 on success and proper error codes on failure
 */
static long mpi3mr_bsg_query_hdb(struct mpi3mr_ioc *mrioc,
				 struct bsg_job *job)
{}


/**
 * mpi3mr_enable_logdata - Handler for log data enable
 * @mrioc: Adapter instance reference
 * @job: BSG job reference
 *
 * This function enables log data caching in the driver if not
 * already enabled and return the maximum number of log data
 * entries that can be cached in the driver.
 *
 * Return: 0 on success and proper error codes on failure
 */
static long mpi3mr_enable_logdata(struct mpi3mr_ioc *mrioc,
	struct bsg_job *job)
{}
/**
 * mpi3mr_get_logdata - Handler for get log data
 * @mrioc: Adapter instance reference
 * @job: BSG job pointer
 * This function copies the log data entries to the user buffer
 * when log caching is enabled in the driver.
 *
 * Return: 0 on success and proper error codes on failure
 */
static long mpi3mr_get_logdata(struct mpi3mr_ioc *mrioc,
	struct bsg_job *job)
{}

/**
 * mpi3mr_bsg_pel_enable - Handler for PEL enable driver
 * @mrioc: Adapter instance reference
 * @job: BSG job pointer
 *
 * This function is the handler for PEL enable driver.
 * Validates the application given class and locale and if
 * requires aborts the existing PEL wait request and/or issues
 * new PEL wait request to the firmware and returns.
 *
 * Return: 0 on success and proper error codes on failure.
 */
static long mpi3mr_bsg_pel_enable(struct mpi3mr_ioc *mrioc,
				  struct bsg_job *job)
{}
/**
 * mpi3mr_get_all_tgt_info - Get all target information
 * @mrioc: Adapter instance reference
 * @job: BSG job reference
 *
 * This function copies the driver managed target devices device
 * handle, persistent ID, bus ID and taret ID to the user
 * provided buffer for the specific controller. This function
 * also provides the number of devices managed by the driver for
 * the specific controller.
 *
 * Return: 0 on success and proper error codes on failure
 */
static long mpi3mr_get_all_tgt_info(struct mpi3mr_ioc *mrioc,
	struct bsg_job *job)
{}
/**
 * mpi3mr_get_change_count - Get topology change count
 * @mrioc: Adapter instance reference
 * @job: BSG job reference
 *
 * This function copies the toplogy change count provided by the
 * driver in events and cached in the driver to the user
 * provided buffer for the specific controller.
 *
 * Return: 0 on success and proper error codes on failure
 */
static long mpi3mr_get_change_count(struct mpi3mr_ioc *mrioc,
	struct bsg_job *job)
{}

/**
 * mpi3mr_bsg_adp_reset - Issue controller reset
 * @mrioc: Adapter instance reference
 * @job: BSG job reference
 *
 * This function identifies the user provided reset type and
 * issues approporiate reset to the controller and wait for that
 * to complete and reinitialize the controller and then returns
 *
 * Return: 0 on success and proper error codes on failure
 */
static long mpi3mr_bsg_adp_reset(struct mpi3mr_ioc *mrioc,
	struct bsg_job *job)
{}

/**
 * mpi3mr_bsg_populate_adpinfo - Get adapter info command handler
 * @mrioc: Adapter instance reference
 * @job: BSG job reference
 *
 * This function provides adapter information for the given
 * controller
 *
 * Return: 0 on success and proper error codes on failure
 */
static long mpi3mr_bsg_populate_adpinfo(struct mpi3mr_ioc *mrioc,
	struct bsg_job *job)
{}

/**
 * mpi3mr_bsg_process_drv_cmds - Driver Command handler
 * @job: BSG job reference
 *
 * This function is the top level handler for driver commands,
 * this does basic validation of the buffer and identifies the
 * opcode and switches to correct sub handler.
 *
 * Return: 0 on success and proper error codes on failure
 */
static long mpi3mr_bsg_process_drv_cmds(struct bsg_job *job)
{}

/**
 * mpi3mr_total_num_ioctl_sges - Count number of SGEs required
 * @drv_bufs: DMA address of the buffers to be placed in sgl
 * @bufcnt: Number of DMA buffers
 *
 * This function returns total number of data SGEs required
 * including zero length SGEs and excluding management request
 * and response buffer for the given list of data buffer
 * descriptors
 *
 * Return: Number of SGE elements needed
 */
static inline u16 mpi3mr_total_num_ioctl_sges(struct mpi3mr_buf_map *drv_bufs,
					      u8 bufcnt)
{}

/**
 * mpi3mr_bsg_build_sgl - SGL construction for MPI commands
 * @mrioc: Adapter instance reference
 * @mpi_req: MPI request
 * @sgl_offset: offset to start sgl in the MPI request
 * @drv_bufs: DMA address of the buffers to be placed in sgl
 * @bufcnt: Number of DMA buffers
 * @is_rmc: Does the buffer list has management command buffer
 * @is_rmr: Does the buffer list has management response buffer
 * @num_datasges: Number of data buffers in the list
 *
 * This function places the DMA address of the given buffers in
 * proper format as SGEs in the given MPI request.
 *
 * Return: 0 on success,-1 on failure
 */
static int mpi3mr_bsg_build_sgl(struct mpi3mr_ioc *mrioc, u8 *mpi_req,
				u32 sgl_offset, struct mpi3mr_buf_map *drv_bufs,
				u8 bufcnt, u8 is_rmc, u8 is_rmr, u8 num_datasges)
{}

/**
 * mpi3mr_get_nvme_data_fmt - returns the NVMe data format
 * @nvme_encap_request: NVMe encapsulated MPI request
 *
 * This function returns the type of the data format specified
 * in user provided NVMe command in NVMe encapsulated request.
 *
 * Return: Data format of the NVMe command (PRP/SGL etc)
 */
static unsigned int mpi3mr_get_nvme_data_fmt(
	struct mpi3_nvme_encapsulated_request *nvme_encap_request)
{}

/**
 * mpi3mr_build_nvme_sgl - SGL constructor for NVME
 *				   encapsulated request
 * @mrioc: Adapter instance reference
 * @nvme_encap_request: NVMe encapsulated MPI request
 * @drv_bufs: DMA address of the buffers to be placed in sgl
 * @bufcnt: Number of DMA buffers
 *
 * This function places the DMA address of the given buffers in
 * proper format as SGEs in the given NVMe encapsulated request.
 *
 * Return: 0 on success, -1 on failure
 */
static int mpi3mr_build_nvme_sgl(struct mpi3mr_ioc *mrioc,
	struct mpi3_nvme_encapsulated_request *nvme_encap_request,
	struct mpi3mr_buf_map *drv_bufs, u8 bufcnt)
{}

/**
 * mpi3mr_build_nvme_prp - PRP constructor for NVME
 *			       encapsulated request
 * @mrioc: Adapter instance reference
 * @nvme_encap_request: NVMe encapsulated MPI request
 * @drv_bufs: DMA address of the buffers to be placed in SGL
 * @bufcnt: Number of DMA buffers
 *
 * This function places the DMA address of the given buffers in
 * proper format as PRP entries in the given NVMe encapsulated
 * request.
 *
 * Return: 0 on success, -1 on failure
 */
static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc,
	struct mpi3_nvme_encapsulated_request *nvme_encap_request,
	struct mpi3mr_buf_map *drv_bufs, u8 bufcnt)
{}

/**
 * mpi3mr_map_data_buffer_dma - build dma descriptors for data
 *                              buffers
 * @mrioc: Adapter instance reference
 * @drv_buf: buffer map descriptor
 * @desc_count: Number of already consumed dma descriptors
 *
 * This function computes how many pre-allocated DMA descriptors
 * are required for the given data buffer and if those number of
 * descriptors are free, then setup the mapping of the scattered
 * DMA address to the given data buffer, if the data direction
 * of the buffer is DMA_TO_DEVICE then the actual data is copied to
 * the DMA buffers
 *
 * Return: 0 on success, -1 on failure
 */
static int mpi3mr_map_data_buffer_dma(struct mpi3mr_ioc *mrioc,
				      struct mpi3mr_buf_map *drv_buf,
				      u16 desc_count)
{}
/**
 * mpi3mr_bsg_process_mpt_cmds - MPI Pass through BSG handler
 * @job: BSG job reference
 *
 * This function is the top level handler for MPI Pass through
 * command, this does basic validation of the input data buffers,
 * identifies the given buffer types and MPI command, allocates
 * DMAable memory for user given buffers, construstcs SGL
 * properly and passes the command to the firmware.
 *
 * Once the MPI command is completed the driver copies the data
 * if any and reply, sense information to user provided buffers.
 * If the command is timed out then issues controller reset
 * prior to returning.
 *
 * Return: 0 on success and proper error codes on failure
 */

static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
{}

/**
 * mpi3mr_app_save_logdata - Save Log Data events
 * @mrioc: Adapter instance reference
 * @event_data: event data associated with log data event
 * @event_data_size: event data size to copy
 *
 * If log data event caching is enabled by the applicatiobns,
 * then this function saves the log data in the circular queue
 * and Sends async signal SIGIO to indicate there is an async
 * event from the firmware to the event monitoring applications.
 *
 * Return:Nothing
 */
void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data,
	u16 event_data_size)
{}

/**
 * mpi3mr_bsg_request - bsg request entry point
 * @job: BSG job reference
 *
 * This is driver's entry point for bsg requests
 *
 * Return: 0 on success and proper error codes on failure
 */
static int mpi3mr_bsg_request(struct bsg_job *job)
{}

/**
 * mpi3mr_bsg_exit - de-registration from bsg layer
 * @mrioc: Adapter instance reference
 *
 * This will be called during driver unload and all
 * bsg resources allocated during load will be freed.
 *
 * Return:Nothing
 */
void mpi3mr_bsg_exit(struct mpi3mr_ioc *mrioc)
{}

/**
 * mpi3mr_bsg_node_release -release bsg device node
 * @dev: bsg device node
 *
 * decrements bsg dev parent reference count
 *
 * Return:Nothing
 */
static void mpi3mr_bsg_node_release(struct device *dev)
{}

/**
 * mpi3mr_bsg_init -  registration with bsg layer
 * @mrioc: Adapter instance reference
 *
 * This will be called during driver load and it will
 * register driver with bsg layer
 *
 * Return:Nothing
 */
void mpi3mr_bsg_init(struct mpi3mr_ioc *mrioc)
{}

/**
 * version_fw_show - SysFS callback for firmware version read
 * @dev: class device
 * @attr: Device attributes
 * @buf: Buffer to copy
 *
 * Return: sysfs_emit() return after copying firmware version
 */
static ssize_t
version_fw_show(struct device *dev, struct device_attribute *attr,
	char *buf)
{}
static DEVICE_ATTR_RO(version_fw);

/**
 * fw_queue_depth_show - SysFS callback for firmware max cmds
 * @dev: class device
 * @attr: Device attributes
 * @buf: Buffer to copy
 *
 * Return: sysfs_emit() return after copying firmware max commands
 */
static ssize_t
fw_queue_depth_show(struct device *dev, struct device_attribute *attr,
			char *buf)
{}
static DEVICE_ATTR_RO(fw_queue_depth);

/**
 * op_req_q_count_show - SysFS callback for request queue count
 * @dev: class device
 * @attr: Device attributes
 * @buf: Buffer to copy
 *
 * Return: sysfs_emit() return after copying request queue count
 */
static ssize_t
op_req_q_count_show(struct device *dev, struct device_attribute *attr,
			char *buf)
{}
static DEVICE_ATTR_RO(op_req_q_count);

/**
 * reply_queue_count_show - SysFS callback for reply queue count
 * @dev: class device
 * @attr: Device attributes
 * @buf: Buffer to copy
 *
 * Return: sysfs_emit() return after copying reply queue count
 */
static ssize_t
reply_queue_count_show(struct device *dev, struct device_attribute *attr,
			char *buf)
{}

static DEVICE_ATTR_RO(reply_queue_count);

/**
 * logging_level_show - Show controller debug level
 * @dev: class device
 * @attr: Device attributes
 * @buf: Buffer to copy
 *
 * A sysfs 'read/write' shost attribute, to show the current
 * debug log level used by the driver for the specific
 * controller.
 *
 * Return: sysfs_emit() return
 */
static ssize_t
logging_level_show(struct device *dev,
	struct device_attribute *attr, char *buf)

{}

/**
 * logging_level_store- Change controller debug level
 * @dev: class device
 * @attr: Device attributes
 * @buf: Buffer to copy
 * @count: size of the buffer
 *
 * A sysfs 'read/write' shost attribute, to change the current
 * debug log level used by the driver for the specific
 * controller.
 *
 * Return: strlen() return
 */
static ssize_t
logging_level_store(struct device *dev,
	struct device_attribute *attr,
	const char *buf, size_t count)
{}
static DEVICE_ATTR_RW(logging_level);

/**
 * adp_state_show() - SysFS callback for adapter state show
 * @dev: class device
 * @attr: Device attributes
 * @buf: Buffer to copy
 *
 * Return: sysfs_emit() return after copying adapter state
 */
static ssize_t
adp_state_show(struct device *dev, struct device_attribute *attr,
	char *buf)
{}

static DEVICE_ATTR_RO(adp_state);

static struct attribute *mpi3mr_host_attrs[] =;

static const struct attribute_group mpi3mr_host_attr_group =;

const struct attribute_group *mpi3mr_host_groups[] =;


/*
 * SCSI Device attributes under sysfs
 */

/**
 * sas_address_show - SysFS callback for dev SASaddress display
 * @dev: class device
 * @attr: Device attributes
 * @buf: Buffer to copy
 *
 * Return: sysfs_emit() return after copying SAS address of the
 * specific SAS/SATA end device.
 */
static ssize_t
sas_address_show(struct device *dev, struct device_attribute *attr,
			char *buf)
{}

static DEVICE_ATTR_RO(sas_address);

/**
 * device_handle_show - SysFS callback for device handle display
 * @dev: class device
 * @attr: Device attributes
 * @buf: Buffer to copy
 *
 * Return: sysfs_emit() return after copying firmware internal
 * device handle of the specific device.
 */
static ssize_t
device_handle_show(struct device *dev, struct device_attribute *attr,
			char *buf)
{}

static DEVICE_ATTR_RO(device_handle);

/**
 * persistent_id_show - SysFS callback for persisten ID display
 * @dev: class device
 * @attr: Device attributes
 * @buf: Buffer to copy
 *
 * Return: sysfs_emit() return after copying persistent ID of the
 * of the specific device.
 */
static ssize_t
persistent_id_show(struct device *dev, struct device_attribute *attr,
			char *buf)
{}
static DEVICE_ATTR_RO(persistent_id);

/**
 * sas_ncq_prio_supported_show - Indicate if device supports NCQ priority
 * @dev: pointer to embedded device
 * @attr: sas_ncq_prio_supported attribute descriptor
 * @buf: the buffer returned
 *
 * A sysfs 'read-only' sdev attribute, only works with SATA devices
 */
static ssize_t
sas_ncq_prio_supported_show(struct device *dev,
			    struct device_attribute *attr, char *buf)
{}
static DEVICE_ATTR_RO(sas_ncq_prio_supported);

/**
 * sas_ncq_prio_enable_show - send prioritized io commands to device
 * @dev: pointer to embedded device
 * @attr: sas_ncq_prio_enable attribute descriptor
 * @buf: the buffer returned
 *
 * A sysfs 'read/write' sdev attribute, only works with SATA devices
 */
static ssize_t
sas_ncq_prio_enable_show(struct device *dev,
				 struct device_attribute *attr, char *buf)
{}

static ssize_t
sas_ncq_prio_enable_store(struct device *dev,
				  struct device_attribute *attr,
				  const char *buf, size_t count)
{}
static DEVICE_ATTR_RW(sas_ncq_prio_enable);

static struct attribute *mpi3mr_dev_attrs[] =;

static const struct attribute_group mpi3mr_dev_attr_group =;

const struct attribute_group *mpi3mr_dev_groups[] =;