tb_seg_alloc_failed: if (mrioc->trace_buf_pool) { for (i = 0; i < mrioc->num_tb_segs; i++) { if (mrioc->trace_buf[i].segment) {
dma_pool_free(mrioc->trace_buf_pool,
mrioc->trace_buf[i].segment,
mrioc->trace_buf[i].segment_dma);
mrioc->trace_buf[i].segment = NULL;
}
mrioc->trace_buf[i].segment = NULL;
}
dma_pool_destroy(mrioc->trace_buf_pool);
mrioc->trace_buf_pool = NULL;
}
trace_buf_pool_failed:
kfree(mrioc->trace_buf);
mrioc->trace_buf = NULL;
trace_buf_failed: if (diag_buffer_list)
dma_free_coherent(&mrioc->pdev->dev, sizeof(u64) * mrioc->num_tb_segs,
diag_buffer_list, diag_buffer_list_dma); return -1;
}
/** * 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)
{ struct diag_buffer_desc *diag_buffer; struct mpi3_driver_page1 driver_pg1;
u32 trace_dec_size, trace_min_size, fw_dec_size, fw_min_size,
trace_size, fw_size;
u16 pg_sz = sizeof(driver_pg1); int retval = 0; bool retry = false;
if (mrioc->diag_buffers[0].addr || mrioc->diag_buffers[1].addr) return;
/** * 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)
{ struct mpi3_diag_buffer_post_request diag_buf_post_req;
u8 prev_status; int retval = 0;
if (diag_buffer->disabled_after_reset) {
dprint_bsg_err(mrioc, "%s: skipping diag buffer posting\n" "as it is disabled after reset\n", __func__); return -1;
}
/** * 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)
{
u8 i; struct diag_buffer_desc *diag_buffer;
for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) {
diag_buffer = &mrioc->diag_buffers[i]; if (!(diag_buffer->addr)) continue; if (mpi3mr_issue_diag_buf_post(mrioc, diag_buffer)) return -1;
} return 0;
}
/** * 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)
{ struct mpi3_diag_buffer_manage_request diag_buf_manage_req; int retval = 0;
if ((diag_buffer->status != MPI3MR_HDB_BUFSTATUS_POSTED_UNPAUSED) &&
(diag_buffer->status != MPI3MR_HDB_BUFSTATUS_POSTED_PAUSED)) return retval;
/** * 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
*/ staticvoid mpi3mr_process_trigger(struct mpi3mr_ioc *mrioc, u8 trigger_type, union mpi3mr_trigger_data *trigger_data, u8 trigger_flags)
{ struct trigger_event_data event_data; struct diag_buffer_desc *trace_hdb = NULL; struct diag_buffer_desc *fw_hdb = NULL;
u64 global_trigger;
if (event_data.trace_hdb || event_data.fw_hdb)
mpi3mr_hdb_trigger_data_event(mrioc, &event_data);
}
/** * 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)
{ unsignedlong flags; union mpi3mr_trigger_data trigger_specific_data;
for (i = 0; i < num_triggers; i++, event_trigger++) { if (event_trigger->type !=
MPI3_DRIVER2_TRIGGER_TYPE_EVENT) continue; if (event_trigger->event != event) continue;
trigger_flags = event_trigger->flags;
mpi3mr_process_trigger(mrioc,
MPI3MR_HDB_TRIGGER_TYPE_ELEMENT,
(union mpi3mr_trigger_data *)event_trigger,
trigger_flags); break;
}
spin_unlock_irqrestore(&mrioc->trigger_lock, flags);
}
}
/** * 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)
{ struct mpi3_driver2_trigger_reply *reply_trigger = NULL;
u64 i = 0; unsignedlong flags;
u8 num_triggers, trigger_flags;
if (mrioc->reply_trigger_present) {
spin_lock_irqsave(&mrioc->trigger_lock, flags);
reply_trigger = (struct mpi3_driver2_trigger_reply *)
mrioc->driver_pg2->trigger;
num_triggers = mrioc->driver_pg2->num_triggers; for (i = 0; i < num_triggers; i++, reply_trigger++) { if (reply_trigger->type !=
MPI3_DRIVER2_TRIGGER_TYPE_REPLY) continue; if ((le16_to_cpu(reply_trigger->ioc_status) !=
ioc_status)
&& (le16_to_cpu(reply_trigger->ioc_status) !=
MPI3_DRIVER2_TRIGGER_REPLY_IOCSTATUS_MATCH_ALL)) continue; if ((le32_to_cpu(reply_trigger->ioc_log_info) !=
(le32_to_cpu(reply_trigger->ioc_log_info_mask) &
ioc_loginfo))) continue;
trigger_flags = reply_trigger->flags;
mpi3mr_process_trigger(mrioc,
MPI3MR_HDB_TRIGGER_TYPE_ELEMENT,
(union mpi3mr_trigger_data *)reply_trigger,
trigger_flags); break;
}
spin_unlock_irqrestore(&mrioc->trigger_lock, flags);
}
}
/** * 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
*/ staticint mpi3mr_get_num_trigger(struct mpi3mr_ioc *mrioc, u8 *num_triggers,
u8 page_action)
{ struct mpi3_driver_page2 drvr_page2; int retval = 0;
/** * 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)
{
u16 pg_sz = sizeof(struct mpi3_driver_page2); struct mpi3_driver_page2 *drvr_page2 = NULL;
u8 trigger_type, num_triggers; int retval; int i = 0; unsignedlong flags;
for (i = 0; (i < mrioc->driver_pg2->num_triggers); i++) {
trigger_type = mrioc->driver_pg2->trigger[i].event.type; switch (trigger_type) { case MPI3_DRIVER2_TRIGGER_TYPE_REPLY:
mrioc->reply_trigger_present = true; break; case MPI3_DRIVER2_TRIGGER_TYPE_EVENT:
mrioc->event_trigger_present = true; break; case MPI3_DRIVER2_TRIGGER_TYPE_SCSI_SENSE:
mrioc->scsisense_trigger_present = true; break; default: break;
}
}
spin_unlock_irqrestore(&mrioc->trigger_lock, flags);
out: return retval;
}
/** * 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)
{
u8 i; struct diag_buffer_desc *diag_buffer;
for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) {
diag_buffer = &mrioc->diag_buffers[i]; if (!(diag_buffer->addr)) continue; if (diag_buffer->status == MPI3MR_HDB_BUFSTATUS_RELEASED) continue; if (!skip_rel_action)
mpi3mr_issue_diag_buf_release(mrioc, diag_buffer);
diag_buffer->status = MPI3MR_HDB_BUFSTATUS_RELEASED;
atomic64_inc(&event_counter);
}
}
/** * mpi3mr_set_trigger_data_in_hdb - Updates HDB trigger type and * trigger data * * @hdb: HDB pointer * @type: Trigger type * @trigger_data: Pointer to trigger data information * @force: Trigger overwrite flag * * 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)
{ if ((!force) && (hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN)) return;
hdb->trigger_type = type; if (!trigger_data)
memset(&hdb->trigger_data, 0, sizeof(*trigger_data)); else
memcpy(&hdb->trigger_data, trigger_data, sizeof(*trigger_data));
}
/** * mpi3mr_set_trigger_data_in_all_hdb - Updates HDB trigger type * and trigger data for all HDB * * @mrioc: Adapter instance reference * @type: Trigger type * @trigger_data: Pointer to trigger data information * @force: Trigger overwrite flag * * 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)
{ struct diag_buffer_desc *hdb = NULL;
out_unlock:
mrioc->pel_abort_cmd.state = MPI3MR_CMD_NOTUSED;
mutex_unlock(&mrioc->pel_abort_cmd.mutex); return retval;
} /** * 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
*/ staticstruct mpi3mr_ioc *mpi3mr_bsg_verify_adapter(int ioc_number)
{ struct mpi3mr_ioc *mrioc = NULL;
/** * 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
*/ staticlong
mpi3mr_bsg_refresh_hdb_triggers(struct mpi3mr_ioc *mrioc, struct bsg_job *job)
{ struct mpi3mr_bsg_out_refresh_hdb_triggers refresh_triggers;
uint32_t data_out_sz;
u8 page_action; long rval = -EINVAL;
/** * 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
*/ staticlong mpi3mr_bsg_repost_hdb(struct mpi3mr_ioc *mrioc, struct bsg_job *job)
{ struct mpi3mr_bsg_out_repost_hdb repost_hdb; struct diag_buffer_desc *diag_buffer;
uint32_t data_out_sz;
data_out_sz = job->request_payload.payload_len;
if (data_out_sz != sizeof(repost_hdb)) {
dprint_bsg_err(mrioc, "%s: invalid size argument\n",
__func__); return -EINVAL;
} if (mrioc->unrecoverable) {
dprint_bsg_err(mrioc, "%s: unrecoverable controller\n",
__func__); return -EFAULT;
} if (mrioc->reset_in_progress) {
dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__); return -EAGAIN;
}
diag_buffer = mpi3mr_diag_buffer_for_type(mrioc, repost_hdb.buf_type); if ((!diag_buffer) || (!diag_buffer->addr)) {
dprint_bsg_err(mrioc, "%s: invalid buffer type %d\n",
__func__, repost_hdb.buf_type); return -EINVAL;
}
if (diag_buffer->status != MPI3MR_HDB_BUFSTATUS_RELEASED) {
dprint_bsg_err(mrioc, "%s: invalid buffer status %d for type %d\n",
__func__, diag_buffer->status, repost_hdb.buf_type); return -EINVAL;
}
if (mpi3mr_issue_diag_buf_post(mrioc, diag_buffer)) {
dprint_bsg_err(mrioc, "%s: post failed for type %d\n",
__func__, repost_hdb.buf_type); return -EFAULT;
}
mpi3mr_set_trigger_data_in_hdb(diag_buffer,
MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1);
return 0;
}
/** * 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
*/ staticlong mpi3mr_bsg_query_hdb(struct mpi3mr_ioc *mrioc, struct bsg_job *job)
{ long rval = 0; struct mpi3mr_bsg_in_hdb_status *hbd_status; struct mpi3mr_hdb_entry *hbd_status_entry;
u32 length, min_length;
u8 i; struct diag_buffer_desc *diag_buffer;
uint32_t data_in_sz = 0;
/** * 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
*/ staticlong mpi3mr_enable_logdata(struct mpi3mr_ioc *mrioc, struct bsg_job *job)
{ struct mpi3mr_logdata_enable logdata_enable;
return -EINVAL;
} /** * 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
*/ staticlong mpi3mr_get_logdata(struct mpi3mr_ioc *mrioc, struct bsg_job *job)
{
u16 num_entries, sz, entry_sz = mrioc->logdata_entry_sz;
if ((!mrioc->logdata_buf) || (job->request_payload.payload_len < entry_sz)) return -EINVAL;
/** * 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.
*/ staticlong mpi3mr_bsg_pel_enable(struct mpi3mr_ioc *mrioc, struct bsg_job *job)
{ long rval = -EINVAL; struct mpi3mr_bsg_out_pel_enable pel_enable;
u8 issue_pel_wait;
u8 tmp_class;
u16 tmp_locale;
out: return rval;
} /** * 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
*/ staticlong mpi3mr_get_all_tgt_info(struct mpi3mr_ioc *mrioc, struct bsg_job *job)
{
u16 num_devices = 0, i = 0, size; unsignedlong flags; struct mpi3mr_tgt_dev *tgtdev; struct mpi3mr_device_map_info *devmap_info = NULL; struct mpi3mr_all_tgt_info *alltgt_info = NULL;
uint32_t min_entrylen = 0, kern_entrylen = 0, usr_entrylen = 0;
sg_copy_from_buffer(job->request_payload.sg_list,
job->request_payload.sg_cnt,
alltgt_info, (min_entrylen + sizeof(u64)));
kfree(alltgt_info); return 0;
} /** * 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
*/ staticlong mpi3mr_get_change_count(struct mpi3mr_ioc *mrioc, struct bsg_job *job)
{ struct mpi3mr_change_count chgcnt;
/** * 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
*/ staticlong mpi3mr_bsg_adp_reset(struct mpi3mr_ioc *mrioc, struct bsg_job *job)
{ long rval = -EINVAL;
u8 save_snapdump; struct mpi3mr_bsg_adp_reset adpreset;
/** * 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
*/ staticlong mpi3mr_bsg_process_drv_cmds(struct bsg_job *job)
{ long rval = -EINVAL; struct mpi3mr_ioc *mrioc = NULL; struct mpi3mr_bsg_packet *bsg_req = NULL; struct mpi3mr_bsg_drv_cmd *drvrcmd = NULL;
if (mutex_lock_interruptible(&mrioc->bsg_cmds.mutex)) return -ERESTARTSYS;
switch (drvrcmd->opcode) { case MPI3MR_DRVBSG_OPCODE_ADPRESET:
rval = mpi3mr_bsg_adp_reset(mrioc, job); break; case MPI3MR_DRVBSG_OPCODE_ALLTGTDEVINFO:
rval = mpi3mr_get_all_tgt_info(mrioc, job); break; case MPI3MR_DRVBSG_OPCODE_GETCHGCNT:
rval = mpi3mr_get_change_count(mrioc, job); break; case MPI3MR_DRVBSG_OPCODE_LOGDATAENABLE:
rval = mpi3mr_enable_logdata(mrioc, job); break; case MPI3MR_DRVBSG_OPCODE_GETLOGDATA:
rval = mpi3mr_get_logdata(mrioc, job); break; case MPI3MR_DRVBSG_OPCODE_PELENABLE:
rval = mpi3mr_bsg_pel_enable(mrioc, job); break; case MPI3MR_DRVBSG_OPCODE_QUERY_HDB:
rval = mpi3mr_bsg_query_hdb(mrioc, job); break; case MPI3MR_DRVBSG_OPCODE_REPOST_HDB:
rval = mpi3mr_bsg_repost_hdb(mrioc, job); break; case MPI3MR_DRVBSG_OPCODE_UPLOAD_HDB:
rval = mpi3mr_bsg_upload_hdb(mrioc, job); break; case MPI3MR_DRVBSG_OPCODE_REFRESH_HDB_TRIGGERS:
rval = mpi3mr_bsg_refresh_hdb_triggers(mrioc, job); break; case MPI3MR_DRVBSG_OPCODE_UNKNOWN: default:
pr_err("%s: unsupported driver command opcode %d\n",
MPI3MR_DRIVER_NAME, drvrcmd->opcode); break;
}
mutex_unlock(&mrioc->bsg_cmds.mutex); return rval;
}
/** * 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
*/ staticinline u16 mpi3mr_total_num_ioctl_sges(struct mpi3mr_buf_map *drv_bufs,
u8 bufcnt)
{
u16 i, sge_count = 0;
for (i = 0; i < bufcnt; i++, drv_bufs++) { if (drv_bufs->data_dir == DMA_NONE ||
drv_bufs->kern_buf) continue;
sge_count += drv_bufs->num_dma_desc; if (!drv_bufs->num_dma_desc)
sge_count++;
} return sge_count;
}
/** * 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
*/ staticint 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)
{ struct mpi3_request_header *mpi_header =
(struct mpi3_request_header *)mpi_req;
u8 *sgl = (mpi_req + sgl_offset), count = 0; struct mpi3_mgmt_passthrough_request *rmgmt_req =
(struct mpi3_mgmt_passthrough_request *)mpi_req; struct mpi3mr_buf_map *drv_buf_iter = drv_bufs;
u8 flag, sgl_flags, sgl_flag_eob, sgl_flags_last, last_chain_sgl_flag;
u16 available_sges, i, sges_needed;
u32 sge_element_size = sizeof(struct mpi3_sge_common); bool chain_used = false;
/** * 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)
*/ staticunsignedint mpi3mr_get_nvme_data_fmt( struct mpi3_nvme_encapsulated_request *nvme_encap_request)
{
u8 format = 0;
format = ((nvme_encap_request->command[0] & 0xc000) >> 14); return format;
}
/** * 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
*/ staticint mpi3mr_build_nvme_sgl(struct mpi3mr_ioc *mrioc, struct mpi3_nvme_encapsulated_request *nvme_encap_request, struct mpi3mr_buf_map *drv_bufs, u8 bufcnt)
{ struct mpi3mr_nvme_pt_sge *nvme_sgl;
__le64 sgl_dma;
u8 count;
size_t length = 0;
u16 available_sges = 0, i;
u32 sge_element_size = sizeof(struct mpi3mr_nvme_pt_sge); struct mpi3mr_buf_map *drv_buf_iter = drv_bufs;
u64 sgemod_mask = ((u64)((mrioc->facts.sge_mod_mask) <<
mrioc->facts.sge_mod_shift) << 32);
u64 sgemod_val = ((u64)(mrioc->facts.sge_mod_value) <<
mrioc->facts.sge_mod_shift) << 32;
u32 size;
/* * Not all commands require a data transfer. If no data, just return * without constructing any sgl.
*/ for (count = 0; count < bufcnt; count++, drv_buf_iter++) { if (drv_buf_iter->data_dir == DMA_NONE) continue;
length = drv_buf_iter->kern_buf_len; break;
} if (!length || !drv_buf_iter->num_dma_desc) return 0;
if (dev_pgsz > MPI3MR_IOCTL_SGE_SIZE) {
dprint_bsg_err(mrioc, "%s: NVMe device page size(%d) is greater than ioctl data sge size(%d) for handle 0x%04x\n",
__func__, dev_pgsz, MPI3MR_IOCTL_SGE_SIZE, dev_handle); return -1;
}
if (MPI3MR_IOCTL_SGE_SIZE % dev_pgsz) {
dprint_bsg_err(mrioc, "%s: ioctl data sge size(%d) is not a multiple of NVMe device page size(%d) for handle 0x%04x\n",
__func__, MPI3MR_IOCTL_SGE_SIZE, dev_pgsz, dev_handle); return -1;
}
/* * Not all commands require a data transfer. If no data, just return * without constructing any PRP.
*/ for (count = 0; count < bufcnt; count++, drv_buf_iter++) { if (drv_buf_iter->data_dir == DMA_NONE) continue;
length = drv_buf_iter->kern_buf_len; break;
}
if (!length || !drv_buf_iter->num_dma_desc) return 0;
for (count = 0; count < drv_buf_iter->num_dma_desc; count++) {
dma_addr = drv_buf_iter->dma_desc[count].dma_addr; if (dma_addr & page_mask) {
dprint_bsg_err(mrioc, "%s:dma_addr %pad is not aligned with page size 0x%x\n",
__func__, &dma_addr, dev_pgsz); return -1;
}
}
if (!mrioc->prp_list_virt) return -1;
mrioc->prp_sz = dev_pgsz;
/* * Set pointers to PRP1 and PRP2, which are in the NVMe command. * PRP1 is located at a 24 byte offset from the start of the NVMe * command. Then set the current PRP entry pointer to PRP1.
*/
prp1_entry = (__le64 *)((u8 *)(nvme_encap_request->command) +
MPI3MR_NVME_CMD_PRP1_OFFSET);
prp2_entry = (__le64 *)((u8 *)(nvme_encap_request->command) +
MPI3MR_NVME_CMD_PRP2_OFFSET);
prp_entry = prp1_entry; /* * For the PRP entries, use the specially allocated buffer of * contiguous memory.
*/
prp_page = (__le64 *)mrioc->prp_list_virt;
prp_page_dma = mrioc->prp_list_dma;
/* * Check if we are within 1 entry of a page boundary we don't * want our first entry to be a PRP List entry.
*/
page_mask_result = (uintptr_t)((u8 *)prp_page + prp_size) & page_mask; if (!page_mask_result) {
dprint_bsg_err(mrioc, "%s: PRP page is not page aligned\n",
__func__); goto err_out;
}
/*
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.29 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.