/* * Number of sectors per IO command * Will be set in megasas_init_mfi if user does not provide
*/ staticunsignedint max_sectors;
module_param_named(max_sectors, max_sectors, int, 0444);
MODULE_PARM_DESC(max_sectors, "Maximum number of sectors per IO command");
staticunsignedint throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH;
module_param(throttlequeuedepth, int, 0444);
MODULE_PARM_DESC(throttlequeuedepth, "Adapter queue depth when throttled due to I/O timeout. Default: 16");
unsignedint resetwaittime = MEGASAS_RESET_WAIT_TIME;
module_param(resetwaittime, int, 0444);
MODULE_PARM_DESC(resetwaittime, "Wait time in (1-180s) after I/O timeout before resetting adapter. Default: 180s");
staticint perf_mode = -1;
module_param(perf_mode, int, 0444);
MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options:\n\t\t" "0 - balanced: High iops and low latency queues are allocated &\n\t\t" "interrupt coalescing is enabled only on high iops queues\n\t\t" "1 - iops: High iops queues are not allocated &\n\t\t" "interrupt coalescing is enabled on all queues\n\t\t" "2 - latency: High iops queues are not allocated &\n\t\t" "interrupt coalescing is disabled on all queues\n\t\t" "default mode is 'balanced'"
);
staticint event_log_level = MFI_EVT_CLASS_CRITICAL;
module_param(event_log_level, int, 0644);
MODULE_PARM_DESC(event_log_level, "Asynchronous event logging level- range is: -2(CLASS_DEBUG) to 4(CLASS_DEAD), Default: 2(CLASS_CRITICAL)");
staticunsignedint enable_sdev_max_qd;
module_param(enable_sdev_max_qd, int, 0444);
MODULE_PARM_DESC(enable_sdev_max_qd, "Enable sdev max qd as can_queue. Default: 0");
staticint poll_queues;
module_param(poll_queues, int, 0444);
MODULE_PARM_DESC(poll_queues, "Number of queues to be use for io_uring poll mode.\n\t\t" "This parameter is effective only if host_tagset_enable=1 &\n\t\t" "It is not applicable for MFI_SERIES. &\n\t\t" "Driver will work in latency mode. &\n\t\t" "High iops queues are not allocated &\n\t\t"
);
u32 megasas_readl(struct megasas_instance *instance, constvolatilevoid __iomem *addr)
{
u32 i = 0, ret_val; /* * Due to a HW errata in Aero controllers, reads to certain * Fusion registers could intermittently return all zeroes. * This behavior is transient in nature and subsequent reads will * return valid value. As a workaround in driver, retry readl for * up to thirty times until a non-zero value is read.
*/ if (instance->adapter_type == AERO_SERIES) { do {
ret_val = readl(addr);
i++;
} while (ret_val == 0 && i < 30); return ret_val;
} else { return readl(addr);
}
}
/** * megasas_set_dma_settings - Populate DMA address, length and flags for DCMDs * @instance: Adapter soft state * @dcmd: DCMD frame inside MFI command * @dma_addr: DMA address of buffer to be passed to FW * @dma_len: Length of DMA buffer to be passed to FW * @return: void
*/ void megasas_set_dma_settings(struct megasas_instance *instance, struct megasas_dcmd_frame *dcmd,
dma_addr_t dma_addr, u32 dma_len)
{ if (instance->consistent_mask_64bit) {
dcmd->sgl.sge64[0].phys_addr = cpu_to_le64(dma_addr);
dcmd->sgl.sge64[0].length = cpu_to_le32(dma_len);
dcmd->flags = cpu_to_le16(dcmd->flags | MFI_FRAME_SGL64);
/** * megasas_get_cmd - Get a command from the free pool * @instance: Adapter soft state * * Returns a free command from the pool
*/ struct megasas_cmd *megasas_get_cmd(struct megasas_instance
*instance)
{ unsignedlong flags; struct megasas_cmd *cmd = NULL;
switch (class) { case MFI_EVT_CLASS_DEBUG: return"debug"; case MFI_EVT_CLASS_PROGRESS: return"progress"; case MFI_EVT_CLASS_INFO: return"info"; case MFI_EVT_CLASS_WARNING: return"WARN"; case MFI_EVT_CLASS_CRITICAL: return"CRIT"; case MFI_EVT_CLASS_FATAL: return"FATAL"; case MFI_EVT_CLASS_DEAD: return"DEAD"; default:
snprintf(buffer, sizeof(buffer), "%d", class); return buffer;
}
}
/** * megasas_decode_evt: Decode FW AEN event and print critical event * for information. * @instance: Adapter soft state
*/ staticvoid
megasas_decode_evt(struct megasas_instance *instance)
{ struct megasas_evt_detail *evt_detail = instance->evt_detail; union megasas_evt_class_locale class_locale;
class_locale.word = le32_to_cpu(evt_detail->cl.word);
if ((event_log_level < MFI_EVT_CLASS_DEBUG) ||
(event_log_level > MFI_EVT_CLASS_DEAD)) {
printk(KERN_WARNING "megaraid_sas: provided event log level is out of range, setting it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n");
event_log_level = MFI_EVT_CLASS_CRITICAL;
}
regs = instance->reg_set;
writel(mask, ®s->outbound_intr_mask); /* Dummy readl to force pci flush */
readl(®s->outbound_intr_mask);
}
/** * megasas_read_fw_status_reg_ppc - returns the current FW status value * @instance: Adapter soft state
*/ static u32
megasas_read_fw_status_reg_ppc(struct megasas_instance *instance)
{ return readl(&instance->reg_set->outbound_scratch_pad_0);
}
regs = instance->reg_set;
writel(mask, ®s->outbound_intr_mask); /* Dummy readl to force pci flush */
readl(®s->outbound_intr_mask);
}
/** * megasas_read_fw_status_reg_skinny - returns the current FW status value * @instance: Adapter soft state
*/ static u32
megasas_read_fw_status_reg_skinny(struct megasas_instance *instance)
{ return readl(&instance->reg_set->outbound_scratch_pad_0);
}
regs = instance->reg_set;
writel(mask, ®s->outbound_intr_mask); /* Dummy readl to force pci flush */
readl(®s->outbound_intr_mask);
}
/** * megasas_read_fw_status_reg_gen2 - returns the current FW status value * @instance: Adapter soft state
*/ static u32
megasas_read_fw_status_reg_gen2(struct megasas_instance *instance)
{ return readl(&instance->reg_set->outbound_scratch_pad_0);
}
/** * megasas_issue_polled - Issues a polling command * @instance: Adapter soft state * @cmd: Command packet to be issued * * For polling, MFI requires the cmd_status to be set to MFI_STAT_INVALID_STATUS before posting.
*/ int
megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
{ struct megasas_header *frame_hdr = &cmd->frame->hdr;
/** * megasas_issue_blocked_cmd - Synchronous wrapper around regular FW cmds * @instance: Adapter soft state * @cmd: Command to be issued * @timeout: Timeout in seconds * * This function waits on an event for the command to be returned from ISR. * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs * Used to issue ioctl commands.
*/ int
megasas_issue_blocked_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, int timeout)
{ int ret = 0;
cmd->cmd_status_drv = DCMD_INIT;
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
__func__, __LINE__); return DCMD_INIT;
}
instance->instancet->issue_dcmd(instance, cmd);
if (timeout) {
ret = wait_event_timeout(instance->int_cmd_wait_q,
cmd->cmd_status_drv != DCMD_INIT, timeout * HZ); if (!ret) {
dev_err(&instance->pdev->dev, "DCMD(opcode: 0x%x) is timed out, func:%s\n",
cmd->frame->dcmd.opcode, __func__); return DCMD_TIMEOUT;
}
} else
wait_event(instance->int_cmd_wait_q,
cmd->cmd_status_drv != DCMD_INIT);
return cmd->cmd_status_drv;
}
/** * megasas_issue_blocked_abort_cmd - Aborts previously issued cmd * @instance: Adapter soft state * @cmd_to_abort: Previously issued cmd to be aborted * @timeout: Timeout in seconds * * MFI firmware can abort previously issued AEN comamnd (automatic event * notification). The megasas_issue_blocked_abort_cmd() issues such abort * cmd and waits for return status. * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
*/ staticint
megasas_issue_blocked_abort_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd_to_abort, int timeout)
{ struct megasas_cmd *cmd; struct megasas_abort_frame *abort_fr; int ret = 0;
u32 opcode;
/** * megasas_make_sgl32 - Prepares 32-bit SGL * @instance: Adapter soft state * @scp: SCSI command from the mid-layer * @mfi_sgl: SGL to be filled in * * If successful, this function returns the number of SG elements. Otherwise, * it returnes -1.
*/ staticint
megasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp, union megasas_sgl *mfi_sgl)
{ int i; int sge_count; struct scatterlist *os_sgl;
/** * megasas_make_sgl64 - Prepares 64-bit SGL * @instance: Adapter soft state * @scp: SCSI command from the mid-layer * @mfi_sgl: SGL to be filled in * * If successful, this function returns the number of SG elements. Otherwise, * it returnes -1.
*/ staticint
megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp, union megasas_sgl *mfi_sgl)
{ int i; int sge_count; struct scatterlist *os_sgl;
/** * megasas_make_sgl_skinny - Prepares IEEE SGL * @instance: Adapter soft state * @scp: SCSI command from the mid-layer * @mfi_sgl: SGL to be filled in * * If successful, this function returns the number of SG elements. Otherwise, * it returnes -1.
*/ staticint
megasas_make_sgl_skinny(struct megasas_instance *instance, struct scsi_cmnd *scp, union megasas_sgl *mfi_sgl)
{ int i; int sge_count; struct scatterlist *os_sgl;
/** * megasas_get_frame_count - Computes the number of frames * @frame_type : type of frame- io or pthru frame * @sge_count : number of sg elements * * Returns the number of frames required for numnber of sge's (sge_count)
*/
static u32 megasas_get_frame_count(struct megasas_instance *instance,
u8 sge_count, u8 frame_type)
{ int num_cnt; int sge_bytes;
u32 sge_sz;
u32 frame_count = 0;
/* * If the command is for the tape device, set the * pthru timeout to the os layer timeout value.
*/ if (scp->device->type == TYPE_TAPE) { if (scsi_cmd_to_rq(scp)->timeout / HZ > 0xFFFF)
pthru->timeout = cpu_to_le16(0xFFFF); else
pthru->timeout = cpu_to_le16(scsi_cmd_to_rq(scp)->timeout / HZ);
}
if (pthru->sge_count > instance->max_num_sge) {
dev_err(&instance->pdev->dev, "DCDB too many SGE NUM=%x\n",
pthru->sge_count); return 0;
}
/* * Sense info specific
*/
pthru->sense_len = SCSI_SENSE_BUFFERSIZE;
pthru->sense_buf_phys_addr_hi =
cpu_to_le32(upper_32_bits(cmd->sense_phys_addr));
pthru->sense_buf_phys_addr_lo =
cpu_to_le32(lower_32_bits(cmd->sense_phys_addr));
/* * Compute the total number of frames this command consumes. FW uses * this number to pull sufficient number of frames from host memory.
*/
cmd->frame_count = megasas_get_frame_count(instance, pthru->sge_count,
PTHRU_FRAME);
return cmd->frame_count;
}
/** * megasas_build_ldio - Prepares IOs to logical devices * @instance: Adapter soft state * @scp: SCSI command * @cmd: Command to be prepared * * Frames (and accompanying SGLs) for regular SCSI IOs use this function.
*/ staticint
megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, struct megasas_cmd *cmd)
{
u32 device_id;
u8 sc = scp->cmnd[0];
u16 flags = 0; struct megasas_io_frame *ldio;
/* * Sense info specific
*/
ldio->sense_len = SCSI_SENSE_BUFFERSIZE;
ldio->sense_buf_phys_addr_hi = 0;
ldio->sense_buf_phys_addr_lo = cpu_to_le32(cmd->sense_phys_addr);
/* * Compute the total number of frames this command consumes. FW uses * this number to pull sufficient number of frames from host memory.
*/
cmd->frame_count = megasas_get_frame_count(instance,
ldio->sge_count, IO_FRAME);
return cmd->frame_count;
}
/** * megasas_cmd_type - Checks if the cmd is for logical drive/sysPD * and whether it's RW or non RW * @cmd: SCSI command *
*/ inlineint megasas_cmd_type(struct scsi_cmnd *cmd)
{ int ret;
switch (cmd->cmnd[0]) { case READ_10: case WRITE_10: case READ_12: case WRITE_12: case READ_6: case WRITE_6: case READ_16: case WRITE_16:
ret = (MEGASAS_IS_LOGICAL(cmd->device)) ?
READ_WRITE_LDIO : READ_WRITE_SYSPDIO; break; default:
ret = (MEGASAS_IS_LOGICAL(cmd->device)) ?
NON_READ_WRITE_LDIO : NON_READ_WRITE_SYSPDIO;
} return ret;
}
/** * megasas_dump_pending_frames - Dumps the frame address of all pending cmds * in FW * @instance: Adapter soft state
*/ staticinlinevoid
megasas_dump_pending_frames(struct megasas_instance *instance)
{ struct megasas_cmd *cmd; int i,n; union megasas_sgl *mfi_sgl; struct megasas_io_frame *ldio; struct megasas_pthru_frame *pthru;
u32 sgcount;
u16 max_cmd = instance->max_fw_cmds;
dev_err(&instance->pdev->dev, "[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);
dev_err(&instance->pdev->dev, "[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding)); if (IS_DMA64)
dev_err(&instance->pdev->dev, "[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no); else
dev_err(&instance->pdev->dev, "[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no);
dev_err(&instance->pdev->dev, "[%d]: Pending OS cmds in FW : \n",instance->host->host_no); for (i = 0; i < max_cmd; i++) {
cmd = instance->cmd_list[i]; if (!cmd->scmd) continue;
dev_err(&instance->pdev->dev, "[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsignedlong)cmd->frame_phys_addr); if (megasas_cmd_type(cmd->scmd) == READ_WRITE_LDIO) {
ldio = (struct megasas_io_frame *)cmd->frame;
mfi_sgl = &ldio->sgl;
sgcount = ldio->sge_count;
dev_err(&instance->pdev->dev, "[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x," " lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",
instance->host->host_no, cmd->frame_count, ldio->cmd, ldio->target_id,
le32_to_cpu(ldio->start_lba_lo), le32_to_cpu(ldio->start_lba_hi),
le32_to_cpu(ldio->sense_buf_phys_addr_lo), sgcount);
} else {
pthru = (struct megasas_pthru_frame *) cmd->frame;
mfi_sgl = &pthru->sgl;
sgcount = pthru->sge_count;
dev_err(&instance->pdev->dev, "[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, " "lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",
instance->host->host_no, cmd->frame_count, pthru->cmd, pthru->target_id,
pthru->lun, pthru->cdb_len, le32_to_cpu(pthru->data_xfer_len),
le32_to_cpu(pthru->sense_buf_phys_addr_lo), sgcount);
} if (megasas_dbg_lvl & MEGASAS_DBG_LVL) { for (n = 0; n < sgcount; n++) { if (IS_DMA64)
dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%llx\n",
le32_to_cpu(mfi_sgl->sge64[n].length),
le64_to_cpu(mfi_sgl->sge64[n].phys_addr)); else
dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%x\n",
le32_to_cpu(mfi_sgl->sge32[n].length),
le32_to_cpu(mfi_sgl->sge32[n].phys_addr));
}
}
} /*for max_cmd*/
dev_err(&instance->pdev->dev, "[%d]: Pending Internal cmds in FW : \n",instance->host->host_no); for (i = 0; i < max_cmd; i++) {
if (is_target_prop && instance->tgt_prop->reset_tmo) { /* * If FW provides a target reset timeout value, driver will use * it. If not set, fallback to default values.
*/
mr_device_priv_data->target_reset_tmo =
min_t(u8, instance->max_reset_tmo,
instance->tgt_prop->reset_tmo);
mr_device_priv_data->task_abort_tmo = instance->task_abort_tmo;
} else {
mr_device_priv_data->target_reset_tmo =
MEGASAS_DEFAULT_TM_TIMEOUT;
mr_device_priv_data->task_abort_tmo =
MEGASAS_DEFAULT_TM_TIMEOUT;
}
}
/* * megasas_set_nvme_device_properties - * set nomerges=2 * set virtual page boundary = 4K (current mr_nvme_pg_size is 4K). * set maximum io transfer = MDTS of NVME device provided by MR firmware. * * MR firmware provides value in KB. Caller of this function converts * kb into bytes. * * e.a MDTS=5 means 2^5 * nvme page size. (In case of 4K page size, * MR firmware provides value 128 as (32 * 4K) = 128K. * * @sdev: scsi device * @max_io_size: maximum io transfer size *
*/ staticinlinevoid
megasas_set_nvme_device_properties(struct scsi_device *sdev, struct queue_limits *lim, u32 max_io_size)
{ struct megasas_instance *instance;
u32 mr_nvme_pg_size;
switch (interface_type) { case SAS_PD:
device_qd = MEGASAS_SAS_QD; break; case SATA_PD:
device_qd = MEGASAS_SATA_QD; break; case NVME_PD:
device_qd = MEGASAS_NVME_QD; break;
}
if (is_target_prop) {
tgt_device_qd = le32_to_cpu(instance->tgt_prop->device_qdepth); if (tgt_device_qd)
device_qd = min(instance->host->can_queue,
(int)tgt_device_qd);
}
if (instance->enable_sdev_max_qd && interface_type != UNKNOWN_DRIVE)
device_qd = instance->host->can_queue;
scsi_change_queue_depth(sdev, device_qd);
}
/* * megasas_set_static_target_properties - * Device property set by driver are static and it is not required to be * updated after OCR. * * set io timeout * set device queue depth * set nvme device properties. see - megasas_set_nvme_device_properties * * @sdev: scsi device * @is_target_prop true, if fw provided target properties.
*/ staticvoid megasas_set_static_target_properties(struct scsi_device *sdev, struct queue_limits *lim, bool is_target_prop)
{
u32 max_io_size_kb = MR_DEFAULT_NVME_MDTS_KB; struct megasas_instance *instance;
/* * The RAID firmware may require extended timeouts.
*/
blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ);
/* max_io_size_kb will be set to non zero for * nvme based vd and syspd.
*/ if (is_target_prop)
max_io_size_kb = le32_to_cpu(instance->tgt_prop->max_io_size_kb);
if (instance->nvme_page_size && max_io_size_kb)
megasas_set_nvme_device_properties(sdev, lim,
max_io_size_kb << 10);
instance = megasas_lookup_instance(sdev->host->host_no); if (instance->pd_list_not_supported) { if (!MEGASAS_IS_LOGICAL(sdev) && sdev->type == TYPE_DISK) {
pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
sdev->id; if (instance->pd_list[pd_index].driveState !=
MR_PD_STATE_SYSTEM) return -ENXIO;
}
}
mutex_lock(&instance->reset_mutex); /* Send DCMD to Firmware and cache the information */ if ((instance->pd_info) && !MEGASAS_IS_LOGICAL(sdev))
megasas_get_pd_info(instance, sdev);
/* Some ventura firmware may not have instance->nvme_page_size set. * Do not send MR_DCMD_DRV_GET_TARGET_PROP
*/ if ((instance->tgt_prop) && (instance->nvme_page_size))
ret_target_prop = megasas_get_target_prop(instance, sdev);
/* Set critical error to block I/O & ioctls in case caller didn't */
atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR); /* Wait 1 second to ensure IO or ioctls in build have posted */
msleep(1000); if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
(instance->adapter_type != MFI_SERIES)) { if (!instance->requestorId) {
writel(MFI_STOP_ADP, &instance->reg_set->doorbell); /* Flush */
readl(&instance->reg_set->doorbell);
} if (instance->requestorId && instance->peerIsPresent)
memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
} else {
writel(MFI_STOP_ADP,
&instance->reg_set->inbound_doorbell);
} /* Complete outstanding ioctls when adapter is killed */
megasas_complete_outstanding_ioctls(instance);
}
/** * megasas_check_and_restore_queue_depth - Check if queue depth needs to be * restored to max value * @instance: Adapter soft state *
*/ void
megasas_check_and_restore_queue_depth(struct megasas_instance *instance)
{ unsignedlong flags;
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.