/* * 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;
if (!cmd) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_vf_affiliation_111:" "Failed to get cmd for scsi%d\n",
instance->host->host_no); return -ENOMEM;
}
dcmd = &cmd->frame->dcmd;
if (!instance->vf_affiliation_111) {
dev_warn(&instance->pdev->dev, "SR-IOV: Couldn't get LD/VF " "affiliation for scsi%d\n", instance->host->host_no);
megasas_return_cmd(instance, cmd); return -ENOMEM;
}
if (initial)
memset(instance->vf_affiliation_111, 0, sizeof(struct MR_LD_VF_AFFILIATION_111)); else {
new_affiliation_111 =
dma_alloc_coherent(&instance->pdev->dev, sizeof(struct MR_LD_VF_AFFILIATION_111),
&new_affiliation_111_h, GFP_KERNEL); if (!new_affiliation_111) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate " "memory for new affiliation for scsi%d\n",
instance->host->host_no);
megasas_return_cmd(instance, cmd); return -ENOMEM;
}
}
dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for " "scsi%d\n", instance->host->host_no);
if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD" " failed with status 0x%x for scsi%d\n",
dcmd->cmd_status, instance->host->host_no);
retval = 1; /* Do a scan if we couldn't get affiliation */ goto out;
}
if (!initial) {
thisVf = new_affiliation_111->thisVf; for (ld = 0 ; ld < new_affiliation_111->vdCount; ld++) if (instance->vf_affiliation_111->map[ld].policy[thisVf] !=
new_affiliation_111->map[ld].policy[thisVf]) {
dev_warn(&instance->pdev->dev, "SR-IOV: " "Got new LD/VF affiliation for scsi%d\n",
instance->host->host_no);
memcpy(instance->vf_affiliation_111,
new_affiliation_111, sizeof(struct MR_LD_VF_AFFILIATION_111));
retval = 1; goto out;
}
}
out: if (new_affiliation_111) {
dma_free_coherent(&instance->pdev->dev, sizeof(struct MR_LD_VF_AFFILIATION_111),
new_affiliation_111,
new_affiliation_111_h);
}
if (!cmd) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_vf_affiliation12: " "Failed to get cmd for scsi%d\n",
instance->host->host_no); return -ENOMEM;
}
dcmd = &cmd->frame->dcmd;
if (!instance->vf_affiliation) {
dev_warn(&instance->pdev->dev, "SR-IOV: Couldn't get LD/VF " "affiliation for scsi%d\n", instance->host->host_no);
megasas_return_cmd(instance, cmd); return -ENOMEM;
}
if (initial)
memset(instance->vf_affiliation, 0, (MAX_LOGICAL_DRIVES + 1) * sizeof(struct MR_LD_VF_AFFILIATION)); else {
new_affiliation =
dma_alloc_coherent(&instance->pdev->dev,
(MAX_LOGICAL_DRIVES + 1) * sizeof(struct MR_LD_VF_AFFILIATION),
&new_affiliation_h, GFP_KERNEL); if (!new_affiliation) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate " "memory for new affiliation for scsi%d\n",
instance->host->host_no);
megasas_return_cmd(instance, cmd); return -ENOMEM;
}
}
dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for " "scsi%d\n", instance->host->host_no);
if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD" " failed with status 0x%x for scsi%d\n",
dcmd->cmd_status, instance->host->host_no);
retval = 1; /* Do a scan if we couldn't get affiliation */ goto out;
}
if (!initial) { if (!new_affiliation->ldCount) {
dev_warn(&instance->pdev->dev, "SR-IOV: Got new LD/VF " "affiliation for passive path for scsi%d\n",
instance->host->host_no);
retval = 1; goto out;
}
newmap = new_affiliation->map;
savedmap = instance->vf_affiliation->map;
thisVf = new_affiliation->thisVf; for (i = 0 ; i < new_affiliation->ldCount; i++) {
found = 0; for (j = 0; j < instance->vf_affiliation->ldCount;
j++) { if (newmap->ref.targetId ==
savedmap->ref.targetId) {
found = 1; if (newmap->policy[thisVf] !=
savedmap->policy[thisVf]) {
doscan = 1; goto out;
}
}
savedmap = (struct MR_LD_VF_MAP *)
((unsignedchar *)savedmap +
savedmap->size);
} if (!found && newmap->policy[thisVf] !=
MR_LD_ACCESS_HIDDEN) {
doscan = 1; goto out;
}
newmap = (struct MR_LD_VF_MAP *)
((unsignedchar *)newmap + newmap->size);
}
/* This function will get the current SR-IOV LD/VF affiliation */ staticint megasas_get_ld_vf_affiliation(struct megasas_instance *instance, int initial)
{ int retval;
/* This function will tell FW to start the SR-IOV heartbeat */ int megasas_sriov_start_heartbeat(struct megasas_instance *instance, int initial)
{ struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; int retval = 0;
cmd = megasas_get_cmd(instance);
if (!cmd) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_sriov_start_heartbeat: " "Failed to get cmd for scsi%d\n",
instance->host->host_no); return -ENOMEM;
}
dcmd = &cmd->frame->dcmd;
if (initial) {
instance->hb_host_mem =
dma_alloc_coherent(&instance->pdev->dev, sizeof(struct MR_CTRL_HB_HOST_MEM),
&instance->hb_host_mem_h,
GFP_KERNEL); if (!instance->hb_host_mem) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate" " memory for heartbeat host memory for scsi%d\n",
instance->host->host_no);
retval = -ENOMEM; goto out;
}
}
if (instance->hb_host_mem->HB.fwCounter !=
instance->hb_host_mem->HB.driverCounter) {
instance->hb_host_mem->HB.driverCounter =
instance->hb_host_mem->HB.fwCounter;
mod_timer(&instance->sriov_heartbeat_timer,
jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
} else {
dev_warn(&instance->pdev->dev, "SR-IOV: Heartbeat never " "completed for scsi%d\n", instance->host->host_no);
schedule_work(&instance->work_init);
}
}
/** * megasas_wait_for_outstanding - Wait for all outstanding cmds * @instance: Adapter soft state * * This function waits for up to MEGASAS_RESET_WAIT_TIME seconds for FW to * complete all its outstanding commands. Returns error if one or more IOs * are pending after this time period. It also marks the controller dead.
*/ staticint megasas_wait_for_outstanding(struct megasas_instance *instance)
{ int i, sl, outstanding;
u32 reset_index;
u32 wait_time = MEGASAS_RESET_WAIT_TIME; unsignedlong flags; struct list_head clist_local; struct megasas_cmd *reset_cmd;
u32 fw_state;
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
dev_info(&instance->pdev->dev, "%s:%d HBA is killed.\n",
__func__, __LINE__); return FAILED;
}
if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
for (i = 0; i < resetwaittime; i++) {
outstanding = atomic_read(&instance->fw_outstanding);
if (!outstanding) break;
if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
dev_notice(&instance->pdev->dev, "[%2d]waiting for %d " "commands to complete\n",i,outstanding); /* * Call cmd completion routine. Cmd to be * be completed directly without depending on isr.
*/
megasas_complete_cmd_dpc((unsignedlong)instance);
}
/** * megasas_generic_reset - Generic reset routine * @scmd: Mid-layer SCSI command * * This routine implements a generic reset handler for device, bus and host * reset requests. Device, bus and host specific reset handlers can use this * function after they do their specific tasks.
*/ staticint megasas_generic_reset(struct scsi_cmnd *scmd)
{ int ret_val; struct megasas_instance *instance;
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
dev_err(&instance->pdev->dev, "cannot recover from previous reset failures\n"); return FAILED;
}
ret_val = megasas_wait_for_outstanding(instance); if (ret_val == SUCCESS)
dev_notice(&instance->pdev->dev, "reset successful\n"); else
dev_err(&instance->pdev->dev, "failed to do reset\n");
return ret_val;
}
/** * megasas_reset_timer - quiesce the adapter if required * @scmd: scsi cmnd * * Sets the FW busy flag and reduces the host->can_queue if the * cmd has not been completed within the timeout period.
*/ staticenum scsi_timeout_action megasas_reset_timer(struct scsi_cmnd *scmd)
{ struct megasas_instance *instance; unsignedlong flags;
/** * megasas_dump - This function will print hexdump of provided buffer. * @buf: Buffer to be dumped * @sz: Size in bytes * @format: Different formats of dumping e.g. format=n will * cause only 'n' 32 bit words to be dumped in a single * line.
*/ inlinevoid
megasas_dump(void *buf, int sz, int format)
{ int i;
__le32 *buf_loc = (__le32 *)buf;
for (i = 0; i < (sz / sizeof(__le32)); i++) { if ((i % format) == 0) { if (i != 0)
printk(KERN_CONT "\n");
printk(KERN_CONT "%08x: ", (i * 4));
}
printk(KERN_CONT "%08x ", le32_to_cpu(buf_loc[i]));
}
printk(KERN_CONT "\n");
}
/** * megasas_dump_reg_set - This function will print hexdump of register set * @reg_set: Register set to be dumped
*/ inlinevoid
megasas_dump_reg_set(void __iomem *reg_set)
{ unsignedint i, sz = 256;
u32 __iomem *reg = (u32 __iomem *)reg_set;
for (i = 0; i < (sz / sizeof(u32)); i++)
printk("%08x: %08x\n", (i * 4), readl(®[i]));
}
/** * megasas_dump_fusion_io - This function will print key details * of SCSI IO * @scmd: SCSI command pointer of SCSI IO
*/ void
megasas_dump_fusion_io(struct scsi_cmnd *scmd)
{ struct megasas_cmd_fusion *cmd = megasas_priv(scmd)->cmd_priv; union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; struct megasas_instance *instance;
/* * megasas_dump_sys_regs - This function will dump system registers through * sysfs. * @reg_set: Pointer to System register set. * @buf: Buffer to which output is to be written. * @return: Number of bytes written to buffer.
*/ staticinline ssize_t
megasas_dump_sys_regs(void __iomem *reg_set, char *buf)
{ unsignedint i, sz = 256; int bytes_wrote = 0; char *loc = (char *)buf;
u32 __iomem *reg = (u32 __iomem *)reg_set;
for (i = 0; i < sz / sizeof(u32); i++) {
bytes_wrote += scnprintf(loc + bytes_wrote,
PAGE_SIZE - bytes_wrote, "%08x: %08x\n", (i * 4),
readl(®[i]));
} return bytes_wrote;
}
/** * megasas_reset_bus_host - Bus & host reset handler entry point * @scmd: Mid-layer SCSI command
*/ staticint megasas_reset_bus_host(struct scsi_cmnd *scmd)
{ int ret; struct megasas_instance *instance;
if (instance->adapter_type != MFI_SERIES)
ret = megasas_task_abort_fusion(scmd); else {
sdev_printk(KERN_NOTICE, scmd->device, "TASK ABORT not supported\n");
ret = FAILED;
}
return ret;
}
/** * megasas_reset_target: Issues target reset request to firmware * (supported only for fusion adapters) * @scmd: SCSI command pointer
*/ staticint megasas_reset_target(struct scsi_cmnd *scmd)
{ int ret; struct megasas_instance *instance;
if (instance->adapter_type != MFI_SERIES)
ret = megasas_reset_target_fusion(scmd); else {
sdev_printk(KERN_NOTICE, scmd->device, "TARGET RESET not supported\n");
ret = FAILED;
}
return ret;
}
/** * megasas_bios_param - Returns disk geometry for a disk * @sdev: device handle * @bdev: block device * @capacity: drive capacity * @geom: geometry parameters
*/ staticint
megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int geom[])
{ int heads; int sectors;
sector_t cylinders; unsignedlong tmp;
/** * megasas_service_aen - Processes an event notification * @instance: Adapter soft state * @cmd: AEN command completed by the ISR * * For AEN, driver sends a command down to FW that is held by the FW till an * event occurs. When an event of interest occurs, FW completes the command * that it was previously holding. * * This routines sends SIGIO signal to processes that have registered with the * driver for AEN.
*/ staticvoid
megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
{ unsignedlong flags;
/* * Don't signal app if it is just an aborted previously registered aen
*/ if ((!cmd->abort_aen) && (instance->unload == 0)) {
spin_lock_irqsave(&poll_aen_lock, flags);
megasas_poll_wait_aen = 1;
spin_unlock_irqrestore(&poll_aen_lock, flags);
wake_up(&megasas_poll_wait);
kill_fasync(&megasas_async_queue, SIGIO, POLL_IN);
} else
cmd->abort_aen = 0;
mutex_lock(&instance->crashdump_lock);
buff_offset = instance->fw_crash_buffer_offset; if (!instance->crash_dump_buf ||
!((instance->fw_crash_state == AVAILABLE) ||
(instance->fw_crash_state == COPYING))) {
dev_err(&instance->pdev->dev, "Firmware crash dump is not available\n");
mutex_unlock(&instance->crashdump_lock); return -EINVAL;
}
if (buff_offset > (instance->fw_crash_buffer_size * dmachunk)) {
dev_err(&instance->pdev->dev, "Firmware crash dump offset is out of range\n");
mutex_unlock(&instance->crashdump_lock); return 0;
}
/** * megasas_complete_int_cmd - Completes an internal command * @instance: Adapter soft state * @cmd: Command to be completed * * The megasas_issue_blocked_cmd() function waits for a command to complete * after it issues a command. This function wakes up that waiting routine by * calling wake_up() on the wait queue.
*/ staticvoid
megasas_complete_int_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
{ if (cmd->cmd_status_drv == DCMD_INIT)
cmd->cmd_status_drv =
(cmd->frame->io.cmd_status == MFI_STAT_OK) ?
DCMD_SUCCESS : DCMD_FAILED;
wake_up(&instance->int_cmd_wait_q);
}
/** * megasas_complete_abort - Completes aborting a command * @instance: Adapter soft state * @cmd: Cmd that was issued to abort another cmd * * The megasas_issue_blocked_abort_cmd() function waits on abort_cmd_wait_q * after it issues an abort on a previously issued command. This function * wakes up all functions waiting on the same wait queue.
*/ staticvoid
megasas_complete_abort(struct megasas_instance *instance, struct megasas_cmd *cmd)
{ if (cmd->sync_cmd) {
cmd->sync_cmd = 0;
cmd->cmd_status_drv = DCMD_SUCCESS;
wake_up(&instance->abort_cmd_wait_q);
}
}
for (i = 0; (i < MEGASAS_MAX_LD_IDS); i++) { if (instance->ld_ids_prev[i] != 0xff &&
instance->ld_ids_from_raidmap[i] == 0xff) { if (megasas_dbg_lvl & LD_PD_DEBUG)
dev_info(&instance->pdev->dev, "LD target ID %d removed from RAID map\n", i);
instance->ld_tgtid_status[i] = LD_TARGET_ID_DELETED;
}
}
}
/** * megasas_complete_cmd - Completes a command * @instance: Adapter soft state * @cmd: Command to be completed * @alt_status: If non-zero, use this value as status to * SCSI mid-layer instead of the value returned * by the FW. This should be used if caller wants * an alternate status (as in the case of aborted * commands)
*/ void
megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
u8 alt_status)
{ int exception = 0; struct megasas_header *hdr = &cmd->frame->hdr; unsignedlong flags; struct fusion_context *fusion = instance->ctrl_context;
u32 opcode, status;
/* flag for the retry reset */
cmd->retry_for_fw_reset = 0;
if (cmd->scmd)
megasas_priv(cmd->scmd)->cmd_priv = NULL;
switch (hdr->cmd) { case MFI_CMD_INVALID: /* Some older 1068 controller FW may keep a pended MR_DCMD_CTRL_EVENT_GET_INFO left over from the main kernel when booting the kdump kernel. Ignore this command to
prevent a kernel panic on shutdown of the kdump kernel. */
dev_warn(&instance->pdev->dev, "MFI_CMD_INVALID command " "completed\n");
dev_warn(&instance->pdev->dev, "If you have a controller " "other than PERC5, please upgrade your firmware\n"); break; case MFI_CMD_PD_SCSI_IO: case MFI_CMD_LD_SCSI_IO:
/* * MFI_CMD_PD_SCSI_IO and MFI_CMD_LD_SCSI_IO could have been * issued either through an IO path or an IOCTL path. If it * was via IOCTL, we will send it to internal completion.
*/ if (cmd->sync_cmd) {
cmd->sync_cmd = 0;
megasas_complete_int_cmd(instance, cmd); break;
}
fallthrough;
case MFI_CMD_SMP: case MFI_CMD_STP: case MFI_CMD_NVME: case MFI_CMD_TOOLBOX:
megasas_complete_int_cmd(instance, cmd); break;
case MFI_CMD_DCMD:
opcode = le32_to_cpu(cmd->frame->dcmd.opcode); /* Check for LD map update */ if ((opcode == MR_DCMD_LD_MAP_GET_INFO)
&& (cmd->frame->dcmd.mbox.b[1] == 1)) {
fusion->fast_path_io = 0;
spin_lock_irqsave(instance->host->host_lock, flags);
status = cmd->frame->hdr.cmd_status;
instance->map_update_cmd = NULL; if (status != MFI_STAT_OK) { if (status != MFI_STAT_NOT_FOUND)
dev_warn(&instance->pdev->dev, "map syncfailed, status = 0x%x\n",
cmd->frame->hdr.cmd_status); else {
megasas_return_cmd(instance, cmd);
spin_unlock_irqrestore(
instance->host->host_lock,
flags); break;
}
}
megasas_return_cmd(instance, cmd);
/* * Set fast path IO to ZERO. * Validate Map will set proper value. * Meanwhile all IOs will go as LD IO.
*/ if (status == MFI_STAT_OK &&
(MR_ValidateMapInfo(instance, (instance->map_id + 1)))) {
instance->map_id++;
fusion->fast_path_io = 1;
} else {
fusion->fast_path_io = 0;
}
if (instance->adapter_type >= INVADER_SERIES)
megasas_set_ld_removed_by_fw(instance);
/* * See if got an event notification
*/ if (opcode == MR_DCMD_CTRL_EVENT_WAIT)
megasas_service_aen(instance, cmd); else
megasas_complete_int_cmd(instance, cmd);
break;
case MFI_CMD_ABORT: /* * Cmd issued to abort another cmd returned
*/
megasas_complete_abort(instance, cmd); break;
while (!list_empty(&clist_local)) {
cmd = list_entry((&clist_local)->next, struct megasas_cmd, list);
list_del_init(&cmd->list);
if (cmd->sync_cmd || cmd->scmd) {
dev_notice(&instance->pdev->dev, "command %p, %p:%d" "detected to be pending while HBA reset\n",
cmd, cmd->scmd, cmd->sync_cmd);
cmd->retry_for_fw_reset++;
if (cmd->retry_for_fw_reset == 3) {
dev_notice(&instance->pdev->dev, "cmd %p, %p:%d" "was tried multiple times during reset." "Shutting down the HBA\n",
cmd, cmd->scmd, cmd->sync_cmd);
instance->instancet->disable_intr(instance);
atomic_set(&instance->fw_reset_no_pci_access, 1);
megaraid_sas_kill_hba(instance); return;
}
}
if (cmd->sync_cmd == 1) { if (cmd->scmd) {
dev_notice(&instance->pdev->dev, "unexpected" "cmd attached to internal command!\n");
}
dev_notice(&instance->pdev->dev, "%p synchronous cmd" "on the internal reset queue," "issue it again.\n", cmd);
cmd->cmd_status_drv = DCMD_INIT;
instance->instancet->fire_cmd(instance,
cmd->frame_phys_addr,
0, instance->reg_set);
} elseif (cmd->scmd) {
dev_notice(&instance->pdev->dev, "%p scsi cmd [%02x]" "detected on the internal queue, issue again.\n",
cmd, cmd->scmd->cmnd[0]);
atomic_inc(&instance->fw_outstanding);
instance->instancet->fire_cmd(instance,
cmd->frame_phys_addr,
cmd->frame_count-1, instance->reg_set);
} else {
dev_notice(&instance->pdev->dev, "%p unexpected cmd on the" "internal reset defer list while re-issue!!\n",
cmd);
}
}
if (instance->aen_cmd) {
dev_notice(&instance->pdev->dev, "aen_cmd in def process\n");
megasas_return_cmd(instance, instance->aen_cmd);
/* * Move the internal reset pending commands to a deferred queue. * * We move the commands pending at internal reset time to a * pending queue. This queue would be flushed after successful * completion of the internal reset sequence. if the internal reset * did not complete in time, the kernel reset handler would flush * these commands.
*/ staticvoid
megasas_internal_reset_defer_cmds(struct megasas_instance *instance)
{ struct megasas_cmd *cmd; int i;
u16 max_cmd = instance->max_fw_cmds;
u32 defer_index; unsignedlong flags;
defer_index = 0;
spin_lock_irqsave(&instance->mfi_pool_lock, flags); for (i = 0; i < max_cmd; i++) {
cmd = instance->cmd_list[i]; if (cmd->sync_cmd == 1 || cmd->scmd) {
dev_notice(&instance->pdev->dev, "moving cmd[%d]:%p:%d:%p" "on the defer queue as internal\n",
defer_index, cmd, cmd->sync_cmd, cmd->scmd);
if (!list_empty(&cmd->list)) {
dev_notice(&instance->pdev->dev, "ERROR while" " moving this cmd:%p, %d %p, it was" "discovered on some list?\n",
cmd, cmd->sync_cmd, cmd->scmd);
if (atomic_read(&instance->adprecovery) != MEGASAS_ADPRESET_SM_INFAULT) {
dev_notice(&instance->pdev->dev, "error, recovery st %x\n",
atomic_read(&instance->adprecovery)); return ;
}
if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
dev_notice(&instance->pdev->dev, "FW detected to be in fault" "state, restarting it...\n");
/** * megasas_deplete_reply_queue - Processes all completed commands * @instance: Adapter soft state * @alt_status: Alternate status to be returned to * SCSI mid-layer instead of the status * returned by the FW * Note: this must be called with hba lock held
*/ staticint
megasas_deplete_reply_queue(struct megasas_instance *instance,
u8 alt_status)
{
u32 mfiStatus;
u32 fw_state;
if (instance->instancet->check_reset(instance, instance->reg_set) == 1) return IRQ_HANDLED;
mfiStatus = instance->instancet->clear_intr(instance); if (mfiStatus == 0) { /* Hardware may not set outbound_intr_status in MSI-X mode */ if (!instance->msix_vectors) return IRQ_NONE;
}
/** * megasas_transition_to_ready - Move the FW to READY state * @instance: Adapter soft state * @ocr: Adapter reset state * * During the initialization, FW passes can potentially be in any one of * several possible states. If the FW in operational, waiting-for-handshake * states, driver must take steps to bring it to ready state. Otherwise, it * has to wait for the ready state.
*/ int
megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
{ int i;
u8 max_wait;
u32 fw_state;
u32 abs_state, curr_abs_state;
/* * The cur_state should not last for more than max_wait secs
*/ for (i = 0; i < max_wait * 50; i++) {
curr_abs_state = instance->instancet->
read_fw_status_reg(instance);
if (abs_state == curr_abs_state) {
msleep(20);
} else break;
}
/* * Return error if fw_state hasn't changed after max_wait
*/ if (curr_abs_state == abs_state) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW state [%d] hasn't changed " "in %d secs\n", fw_state, max_wait);
dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
megasas_dump_reg_set(instance->reg_set); return -ENODEV;
}
abs_state = curr_abs_state;
fw_state = curr_abs_state & MFI_STATE_MASK;
}
dev_info(&instance->pdev->dev, "FW now in Ready state\n");
return 0;
}
/** * megasas_teardown_frame_pool - Destroy the cmd frame DMA pool * @instance: Adapter soft state
*/ staticvoid megasas_teardown_frame_pool(struct megasas_instance *instance)
{ int i;
u16 max_cmd = instance->max_mfi_cmds; struct megasas_cmd *cmd;
if (!instance->frame_dma_pool) return;
/* * Return all frames to pool
*/ for (i = 0; i < max_cmd; i++) {
cmd = instance->cmd_list[i];
if (cmd->frame)
dma_pool_free(instance->frame_dma_pool, cmd->frame,
cmd->frame_phys_addr);
if (cmd->sense)
dma_pool_free(instance->sense_dma_pool, cmd->sense,
cmd->sense_phys_addr);
}
/* * Now destroy the pool itself
*/
dma_pool_destroy(instance->frame_dma_pool);
dma_pool_destroy(instance->sense_dma_pool);
/** * megasas_create_frame_pool - Creates DMA pool for cmd frames * @instance: Adapter soft state * * Each command packet has an embedded DMA memory buffer that is used for * filling MFI frame and the SG list that immediately follows the frame. This * function creates those DMA memory buffers for each command packet by using * PCI pool facility.
*/ staticint megasas_create_frame_pool(struct megasas_instance *instance)
{ int i;
u16 max_cmd;
u32 frame_count; struct megasas_cmd *cmd;
max_cmd = instance->max_mfi_cmds;
/* * For MFI controllers. * max_num_sge = 60 * max_sge_sz = 16 byte (sizeof megasas_sge_skinny) * Total 960 byte (15 MFI frame of 64 byte) * * Fusion adapter require only 3 extra frame. * max_num_sge = 16 (defined as MAX_IOCTL_SGE) * max_sge_sz = 12 byte (sizeof megasas_sge64) * Total 192 byte (3 MFI frame of 64 byte)
*/
frame_count = (instance->adapter_type == MFI_SERIES) ?
(15 + 1) : (3 + 1);
instance->mfi_frame_size = MEGAMFI_FRAME_SIZE * frame_count; /* * Use DMA pool facility provided by PCI layer
*/
instance->frame_dma_pool = dma_pool_create("megasas frame pool",
&instance->pdev->dev,
instance->mfi_frame_size, 256, 0);
if (!instance->frame_dma_pool) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup frame pool\n"); return -ENOMEM;
}
instance->sense_dma_pool = dma_pool_create("megasas sense pool",
&instance->pdev->dev, 128,
4, 0);
if (!instance->sense_dma_pool) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool\n");
/* * Allocate and attach a frame to each of the commands in cmd_list. * By making cmd->index as the context instead of the &cmd, we can * always use 32bit context regardless of the architecture
*/ for (i = 0; i < max_cmd; i++) {
/** * megasas_free_cmds - Free all the cmds in the free cmd pool * @instance: Adapter soft state
*/ void megasas_free_cmds(struct megasas_instance *instance)
{ int i;
/* First free the MFI frame pool */
megasas_teardown_frame_pool(instance);
/* Free all the commands in the cmd_list */ for (i = 0; i < instance->max_mfi_cmds; i++)
/** * megasas_alloc_cmds - Allocates the command packets * @instance: Adapter soft state * * Each command that is issued to the FW, whether IO commands from the OS or * internal commands like IOCTLs, are wrapped in local data structure called * megasas_cmd. The frame embedded in this megasas_cmd is actually issued to * the FW. * * Each frame has a 32-bit field called context (tag). This context is used * to get back the megasas_cmd from the frame when a frame gets completed in * the ISR. Typically the address of the megasas_cmd itself would be used as * the context. But we wanted to keep the differences between 32 and 64 bit * systems to the mininum. We always use 32 bit integers for the context. In * this driver, the 32 bit values are the indices into an array cmd_list. * This array is used only to look up the megasas_cmd given the context. The * free commands themselves are maintained in a linked list called cmd_pool.
*/ int megasas_alloc_cmds(struct megasas_instance *instance)
{ int i; int j;
u16 max_cmd; struct megasas_cmd *cmd;
max_cmd = instance->max_mfi_cmds;
/* * instance->cmd_list is an array of struct megasas_cmd pointers. * Allocate the dynamic array first and then allocate individual * commands.
*/
instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL);
if (!instance->cmd_list) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory\n"); return -ENOMEM;
}
for (i = 0; i < max_cmd; i++) {
instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
GFP_KERNEL);
if (!instance->cmd_list[i]) {
for (j = 0; j < i; j++)
kfree(instance->cmd_list[j]);
for (i = 0; i < max_cmd; i++) {
cmd = instance->cmd_list[i];
memset(cmd, 0, sizeof(struct megasas_cmd));
cmd->index = i;
cmd->scmd = NULL;
cmd->instance = instance;
list_add_tail(&cmd->list, &instance->cmd_pool);
}
/* * Create a frame pool and assign one frame to each cmd
*/ if (megasas_create_frame_pool(instance)) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n");
megasas_free_cmds(instance); return -ENOMEM;
}
return 0;
}
/* * dcmd_timeout_ocr_possible - Check if OCR is possible based on Driver/FW state. * @instance: Adapter soft state * * Return 0 for only Fusion adapter, if driver load/unload is not in progress * or FW is not under OCR.
*/ inlineint
dcmd_timeout_ocr_possible(struct megasas_instance *instance) {
switch (dcmd_timeout_ocr_possible(instance)) { case INITIATE_OCR:
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
mutex_unlock(&instance->reset_mutex);
megasas_reset_fusion(instance->host,
MFI_IO_TIMEOUT_OCR);
mutex_lock(&instance->reset_mutex); break; case KILL_ADAPTER:
megaraid_sas_kill_hba(instance); break; case IGNORE_TIMEOUT:
dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
__func__, __LINE__); break;
}
break;
}
if (ret != DCMD_TIMEOUT)
megasas_return_cmd(instance, cmd);
return;
} /* * megasas_get_pd_list_info - Returns FW's pd_list structure * @instance: Adapter soft state * @pd_list: pd_list structure * * Issues an internal command (DCMD) to get the FW's controller PD * list structure. This information is mainly used to find out SYSTEM * supported by the FW.
*/ staticint
megasas_get_pd_list(struct megasas_instance *instance)
{ int ret = 0, pd_index = 0; struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; struct MR_PD_LIST *ci; struct MR_PD_ADDRESS *pd_addr;
if (instance->pd_list_not_supported) {
dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY " "not supported by firmware\n"); return ret;
}
ci = instance->pd_list_buf;
cmd = megasas_get_cmd(instance);
if (!cmd) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "(get_pd_list): Failed to get cmd\n"); return -ENOMEM;
}
if (ret != DCMD_TIMEOUT)
megasas_return_cmd(instance, cmd);
return ret;
}
/* * megasas_get_ld_list_info - Returns FW's ld_list structure * @instance: Adapter soft state * @ld_list: ld_list structure * * Issues an internal command (DCMD) to get the FW's controller PD * list structure. This information is mainly used to find out SYSTEM * supported by the FW.
*/ staticint
megasas_get_ld_list(struct megasas_instance *instance)
{ int ret = 0, ld_index = 0, ids = 0; struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; struct MR_LD_LIST *ci;
dma_addr_t ci_h = 0;
u32 ld_count;
ci = instance->ld_list_buf;
ci_h = instance->ld_list_buf_h;
cmd = megasas_get_cmd(instance);
if (!cmd) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_list: Failed to get cmd\n"); return -ENOMEM;
}
if (ret != DCMD_TIMEOUT)
megasas_return_cmd(instance, cmd);
return ret;
}
/** * megasas_ld_list_query - Returns FW's ld_list structure * @instance: Adapter soft state * @query_type: ld_list structure type * * Issues an internal command (DCMD) to get the FW's controller PD * list structure. This information is mainly used to find out SYSTEM * supported by the FW.
*/ staticint
megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
{ int ret = 0, ld_index = 0, ids = 0; struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; struct MR_LD_TARGETID_LIST *ci;
dma_addr_t ci_h = 0;
u32 tgtid_count;
ci = instance->ld_targetid_list_buf;
ci_h = instance->ld_targetid_list_buf_h;
cmd = megasas_get_cmd(instance);
if (!cmd) {
dev_warn(&instance->pdev->dev, "megasas_ld_list_query: Failed to get cmd\n"); return -ENOMEM;
}
case DCMD_TIMEOUT: switch (dcmd_timeout_ocr_possible(instance)) { case INITIATE_OCR:
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
mutex_unlock(&instance->reset_mutex);
megasas_reset_fusion(instance->host,
MFI_IO_TIMEOUT_OCR);
mutex_lock(&instance->reset_mutex); break; case KILL_ADAPTER:
megaraid_sas_kill_hba(instance); break; case IGNORE_TIMEOUT:
dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
__func__, __LINE__); break;
}
}
if (ret != DCMD_TIMEOUT)
megasas_return_cmd(instance, cmd);
}
/** * megasas_get_ctrl_info - Returns FW's controller structure * @instance: Adapter soft state * * Issues an internal command (DCMD) to get the FW's controller structure. * This information is mainly used to find out the maximum IO transfer per * command supported by the FW.
*/ int
megasas_get_ctrl_info(struct megasas_instance *instance)
{ int ret = 0; struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; struct megasas_ctrl_info *ci;
dma_addr_t ci_h = 0;
ci = instance->ctrl_info_buf;
ci_h = instance->ctrl_info_buf_h;
cmd = megasas_get_cmd(instance);
if (!cmd) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get a free cmd\n"); return -ENOMEM;
}
if ((instance->adapter_type != MFI_SERIES) &&
!instance->mask_interrupts) {
ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
} else {
ret = megasas_issue_polled(instance, cmd);
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
}
switch (ret) { case DCMD_SUCCESS: /* Save required controller information in * CPU endianness format.
*/
le32_to_cpus((u32 *)&ci->properties.OnOffProperties);
le16_to_cpus((u16 *)&ci->properties.on_off_properties2);
le32_to_cpus((u32 *)&ci->adapterOperations2);
le32_to_cpus((u32 *)&ci->adapterOperations3);
le16_to_cpus((u16 *)&ci->adapter_operations4);
le32_to_cpus((u32 *)&ci->adapter_operations5);
/* Update the latest Ext VD info. * From Init path, store current firmware details. * From OCR path, detect any firmware properties changes. * in case of Firmware upgrade without system reboot.
*/
megasas_update_ext_vd_details(instance);
instance->support_seqnum_jbod_fp =
ci->adapterOperations3.useSeqNumJbodFP;
instance->support_morethan256jbod =
ci->adapter_operations4.support_pd_map_target_id;
instance->support_nvme_passthru =
ci->adapter_operations4.support_nvme_passthru;
instance->support_pci_lane_margining =
ci->adapter_operations5.support_pci_lane_margining;
instance->task_abort_tmo = ci->TaskAbortTO;
instance->max_reset_tmo = ci->MaxResetTO;
/*Check whether controller is iMR or MR */
instance->is_imr = (ci->memory_size ? 0 : 1);
case DCMD_TIMEOUT: switch (dcmd_timeout_ocr_possible(instance)) { case INITIATE_OCR:
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
mutex_unlock(&instance->reset_mutex);
megasas_reset_fusion(instance->host,
MFI_IO_TIMEOUT_OCR);
mutex_lock(&instance->reset_mutex); break; case KILL_ADAPTER:
megaraid_sas_kill_hba(instance); break; case IGNORE_TIMEOUT:
dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
__func__, __LINE__); break;
} break; case DCMD_FAILED:
megaraid_sas_kill_hba(instance); break;
}
if (ret != DCMD_TIMEOUT)
megasas_return_cmd(instance, cmd);
return ret;
}
/* * megasas_set_crash_dump_params - Sends address of crash dump DMA buffer * to firmware * * @instance: Adapter soft state * @crash_buf_state - tell FW to turn ON/OFF crash dump feature MR_CRASH_BUF_TURN_OFF = 0 MR_CRASH_BUF_TURN_ON = 1 * @return 0 on success non-zero on failure. * Issues an internal command (DCMD) to set parameters for crash dump feature. * Driver will send address of crash dump DMA buffer and set mbox to tell FW * that driver supports crash dump feature. This DCMD will be sent only if * crash dump feature is supported by the FW. *
*/ int megasas_set_crash_dump_params(struct megasas_instance *instance,
u8 crash_buf_state)
{ int ret = 0; struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd;
cmd = megasas_get_cmd(instance);
if (!cmd) {
dev_err(&instance->pdev->dev, "Failed to get a free cmd\n"); return -ENOMEM;
}
/* * Prepare a init frame. Note the init frame points to queue info * structure. Each frame has SGL allocated after first 64 bytes. For * this frame - since we don't need any SGL - we use SGL's space as * queue info structure * * We will not get a NULL command below. We just created the pool.
*/
cmd = megasas_get_cmd(instance);
/* * Get various operational parameters from status register
*/
instance->max_fw_cmds = instance->instancet->read_fw_status_reg(instance) & 0x00FFFF; /* * Reduce the max supported cmds by 1. This is to ensure that the * reply_q_sz (1 more than the max cmd that driver may send) * does not exceed max cmds that the FW can support
*/
instance->max_fw_cmds = instance->max_fw_cmds-1;
instance->max_mfi_cmds = instance->max_fw_cmds;
instance->max_num_sge = (instance->instancet->read_fw_status_reg(instance) & 0xFF0000) >>
0x10; /* * For MFI skinny adapters, MEGASAS_SKINNY_INT_CMDS commands * are reserved for IOCTL + driver's internal DCMDs.
*/ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
instance->max_scsi_cmds = (instance->max_fw_cmds -
MEGASAS_SKINNY_INT_CMDS);
sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS);
} else {
instance->max_scsi_cmds = (instance->max_fw_cmds -
MEGASAS_INT_CMDS);
sema_init(&instance->ioctl_sem, (MEGASAS_MFI_IOCTL_CMDS));
}
instance->cur_can_queue = instance->max_scsi_cmds; /* * Create a pool of commands
*/ if (megasas_alloc_cmds(instance)) goto fail_alloc_cmds;
/* * Allocate memory for reply queue. Length of reply queue should * be _one_ more than the maximum commands handled by the firmware. * * Note: When FW completes commands, it places corresponding contex * values in this circular reply queue. This circular queue is a fairly * typical producer-consumer queue. FW is the producer (of completed * commands) and the driver is the consumer.
*/
context_sz = sizeof(u32);
reply_q_sz = context_sz * (instance->max_fw_cmds + 1);
if (!instance->reply_queue) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "Out of DMA mem for reply queue\n"); goto fail_reply_queue;
}
if (megasas_issue_init_mfi(instance)) goto fail_fw_init;
if (megasas_get_ctrl_info(instance)) {
dev_err(&instance->pdev->dev, "(%d): Could get controller info " "Fail from %s %d\n", instance->unique_id,
__func__, __LINE__); goto fail_fw_init;
}
int i; int count; struct megasas_irq_context *irq_ctx;
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; if (instance->adapter_type != MFI_SERIES) { for (i = 0; i < count; i++) {
irq_ctx = &instance->irq_context[i];
irq_poll_disable(&irq_ctx->irqpoll);
}
}
if (instance->msix_vectors) for (i = 0; i < instance->msix_vectors; i++) { if (i < instance->low_latency_index_start)
irq_update_affinity_hint(
pci_irq_vector(instance->pdev, i), NULL);
free_irq(pci_irq_vector(instance->pdev, i),
&instance->irq_context[i]);
} else
free_irq(pci_irq_vector(instance->pdev, 0),
&instance->irq_context[0]);
}
/** * megasas_setup_jbod_map - setup jbod map for FP seq_number. * @instance: Adapter soft state * * Return 0 on success.
*/ void
megasas_setup_jbod_map(struct megasas_instance *instance)
{ int i; struct fusion_context *fusion = instance->ctrl_context;
size_t pd_seq_map_sz;
/** * megasas_get_device_list - Get the PD and LD device list from FW. * @instance: Adapter soft state * @return: Success or failure * * Issue DCMDs to Firmware to get the PD and LD list. * Based on the FW support, driver sends the HOST_DEVICE_LIST or combination * of PD_LIST/LD_LIST_QUERY DCMDs to get the device list.
*/ static int megasas_get_device_list(struct megasas_instance *instance)
{ if (instance->enable_fw_dev_list) { if (megasas_host_device_list_query(instance, true)) return FAILED;
} else { if (megasas_get_pd_list(instance) < 0) {
dev_err(&instance->pdev->dev, "failed to get PD list\n"); return FAILED;
}
if (megasas_ld_list_query(instance,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) {
dev_err(&instance->pdev->dev, "failed to get LD list\n"); return FAILED;
}
}
return SUCCESS;
}
/** * megasas_set_high_iops_queue_affinity_and_hint - Set affinity and hint * for high IOPS queues * @instance: Adapter soft state * return: void
*/ staticinlinevoid
megasas_set_high_iops_queue_affinity_and_hint(struct megasas_instance *instance)
{ int i; unsignedint irq; conststruct cpumask *mask;
if (instance->perf_mode == MR_BALANCED_PERF_MODE) { int nid = dev_to_node(&instance->pdev->dev);
if (nid == NUMA_NO_NODE)
nid = 0;
mask = cpumask_of_node(nid);
for (i = 0; i < instance->low_latency_index_start; i++) {
irq = pci_irq_vector(instance->pdev, i);
irq_set_affinity_and_hint(irq, mask);
}
}
}
/* Do not allocate msix vectors for poll_queues. * msix_vectors is always within a range of FW supported reply queue.
*/
i = pci_alloc_irq_vectors_affinity(instance->pdev,
instance->low_latency_index_start,
instance->msix_vectors - instance->iopoll_q_count, irq_flags, descp);
switch (instance->adapter_type) { case VENTURA_SERIES:
fusion->pcie_bw_limitation = true; break; case AERO_SERIES:
fusion->r56_div_offload = true; break; default: break;
}
/* Check if MSI-X is supported while in ready state */
msix_enable = (instance->instancet->read_fw_status_reg(instance) &
0x4000000) >> 0x1a; if (msix_enable && !msix_disable) {
/* * For Aero (if some conditions are met), driver will configure a * few additional reply queues with interrupt coalescing enabled. * These queues with interrupt coalescing enabled are called * High IOPS queues and rest of reply queues (based on number of * logical CPUs) are termed as Low latency queues. * * Total Number of reply queues = High IOPS queues + low latency queues * * For rest of fusion adapters, 1 additional reply queue will be * reserved for management commands, rest of reply queues * (based on number of logical CPUs) will be used for IOs and * referenced as IO queues. * Total Number of reply queues = 1 + IO queues * * MFI adapters supports single MSI-x so single reply queue * will be used for IO and management commands.
*/
/* * For Aero, if PCIe link speed is <16 GT/s, then driver should operate * in latency perf mode and enable R1 PCI bandwidth algorithm
*/ if (speed < 0x4) {
instance->perf_mode = MR_LATENCY_PERF_MODE;
fusion->pcie_bw_limitation = true;
}
/* * Performance mode settings provided through module parameter-perf_mode will * take affect only for: * 1. Aero family of adapters. * 2. When user sets module parameter- perf_mode in range of 0-2.
*/ if ((perf_mode >= MR_BALANCED_PERF_MODE) &&
(perf_mode <= MR_LATENCY_PERF_MODE))
instance->perf_mode = perf_mode; /* * If intr coalescing is not supported by controller FW, then IOPS * and Balanced modes are not feasible.
*/ if (!intr_coalescing)
instance->perf_mode = MR_LATENCY_PERF_MODE;
megasas_alloc_irq_vectors(instance); if (!instance->msix_vectors)
instance->msix_load_balance = false;
} /* * MSI-X host index 0 is common for all adapter. * It is used for all MPT based Adapters.
*/ if (instance->msix_combined) {
instance->reply_post_host_index_addr[0] =
(u32 *)((u8 *)instance->reg_set +
MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET);
} else {
instance->reply_post_host_index_addr[0] =
(u32 *)((u8 *)instance->reg_set +
MPI2_REPLY_POST_HOST_INDEX_OFFSET);
}
if (!instance->msix_vectors) {
i = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_INTX); if (i < 0) goto fail_init_adapter;
}
/* stream detection initialization */ if (instance->adapter_type >= VENTURA_SERIES) {
fusion->stream_detect_by_ld =
kcalloc(MAX_LOGICAL_DRIVES_EXT, sizeof(struct LD_STREAM_DETECT *),
GFP_KERNEL); if (!fusion->stream_detect_by_ld) {
dev_err(&instance->pdev->dev, "unable to allocate stream detection for pool of LDs\n"); goto fail_get_ld_pd_list;
} for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i) {
fusion->stream_detect_by_ld[i] =
kzalloc(sizeof(struct LD_STREAM_DETECT),
GFP_KERNEL); if (!fusion->stream_detect_by_ld[i]) {
dev_err(&instance->pdev->dev, "unable to allocate stream detect by LD\n"); for (j = 0; j < i; ++j)
kfree(fusion->stream_detect_by_ld[j]);
kfree(fusion->stream_detect_by_ld);
fusion->stream_detect_by_ld = NULL; goto fail_get_ld_pd_list;
}
fusion->stream_detect_by_ld[i]->mru_bit_map
= MR_STREAM_BITMAP;
}
}
/* * Compute the max allowed sectors per IO: The controller info has two * limits on max sectors. Driver should use the minimum of these two. * * 1 << stripe_sz_ops.min = max sectors per strip * * Note that older firmwares ( < FW ver 30) didn't report information * to calculate max_sectors_1. So the number ended up as zero always.
*/
tmp_sectors = 0;
ctrl_info = instance->ctrl_info_buf;
/* * Create and start watchdog thread which will monitor * controller state every 1 sec and trigger OCR when * it enters fault state
*/ if (instance->adapter_type != MFI_SERIES) if (megasas_fusion_start_watchdog(instance) != SUCCESS) goto fail_start_watchdog;
/** * megasas_get_seq_num - Gets latest event sequence numbers * @instance: Adapter soft state * @eli: FW event log sequence numbers information * * FW maintains a log of all events in a non-volatile area. Upper layers would * usually find out the latest sequence number of the events, the seq number at * the boot etc. They would "read" all the events below the latest seq number * by issuing a direct fw cmd (DCMD). For the future events (beyond latest seq * number), they would subsribe to AEN (asynchronous event notification) and * wait for the events to happen.
*/ staticint
megasas_get_seq_num(struct megasas_instance *instance, struct megasas_evt_log_info *eli)
{ struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; struct megasas_evt_log_info *el_info;
dma_addr_t el_info_h = 0; int ret;
/** * megasas_register_aen - Registers for asynchronous event notification * @instance: Adapter soft state * @seq_num: The starting sequence number * @class_locale_word: Class of the event * * This function subscribes for AEN for events beyond the @seq_num. It requests * to be notified if and only if the event is of type @class_locale
*/ staticint
megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
u32 class_locale_word)
{ int ret_val; struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; union megasas_evt_class_locale curr_aen; union megasas_evt_class_locale prev_aen;
/* * If there an AEN pending already (aen_cmd), check if the * class_locale of that pending AEN is inclusive of the new * AEN request we currently have. If it is, then we don't have * to do anything. In other words, whichever events the current * AEN request is subscribing to, have already been subscribed * to. * * If the old_cmd is _not_ inclusive, then we have to abort * that command, form a class_locale that is superset of both * old and current and re-issue to the FW
*/
if ((curr_aen.members.class < MFI_EVT_CLASS_DEBUG) ||
(curr_aen.members.class > MFI_EVT_CLASS_DEAD)) {
dev_info(&instance->pdev->dev, "%s %d out of range class %d send by application\n",
__func__, __LINE__, curr_aen.members.class); return 0;
}
/* * A class whose enum value is smaller is inclusive of all * higher values. If a PROGRESS (= -1) was previously * registered, then a new registration requests for higher * classes need not be sent to FW. They are automatically * included. * * Locale numbers don't have such hierarchy. They are bitmap * values
*/ if ((prev_aen.members.class <= curr_aen.members.class) &&
!((prev_aen.members.locale & curr_aen.members.locale) ^
curr_aen.members.locale)) { /* * Previously issued event registration includes * current request. Nothing to do.
*/ return 0;
} else {
curr_aen.members.locale |= prev_aen.members.locale;
if (prev_aen.members.class < curr_aen.members.class)
curr_aen.members.class = prev_aen.members.class;
if (instance->aen_cmd != NULL) {
megasas_return_cmd(instance, cmd); return 0;
}
/* * Store reference to the cmd used to register for AEN. When an * application wants us to register for AEN, we have to abort this * cmd and re-register with a new EVENT LOCALE supplied by that app
*/
instance->aen_cmd = cmd;
/* * Issue the aen registration frame
*/
instance->instancet->issue_dcmd(instance, cmd);
return 0;
}
/* megasas_get_target_prop - Send DCMD with below details to firmware. * * This DCMD will fetch few properties of LD/system PD defined * in MR_TARGET_DEV_PROPERTIES. eg. Queue Depth, MDTS value. * * DCMD send by drivers whenever new target is added to the OS. * * dcmd.opcode - MR_DCMD_DEV_GET_TARGET_PROP * dcmd.mbox.b[0] - DCMD is to be fired for LD or system PD. * 0 = system PD, 1 = LD. * dcmd.mbox.s[1] - TargetID for LD/system PD. * dcmd.sge IN - Pointer to return MR_TARGET_DEV_PROPERTIES. * * @instance: Adapter soft state * @sdev: OS provided scsi device * * Returns 0 on success non-zero on failure.
*/ int
megasas_get_target_prop(struct megasas_instance *instance, struct scsi_device *sdev)
{ int ret; struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd;
u16 targetId = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) +
sdev->id;
cmd = megasas_get_cmd(instance);
if (!cmd) {
dev_err(&instance->pdev->dev, "Failed to get cmd %s\n", __func__); return -ENOMEM;
}
/* Use shared host tagset only for fusion adaptors * if there are managed interrupts (smp affinity enabled case). * Single msix_vectors in kdump, so shared host tag is also disabled.
*/
dev_info(&instance->pdev->dev, "Max firmware commands: %d shared with default " "hw_queues = %d poll_queues %d\n", instance->max_fw_cmds,
host->nr_hw_queues - instance->iopoll_q_count,
instance->iopoll_q_count); /* * Notify the mid-layer about the new controller
*/ if (scsi_add_host(host, &instance->pdev->dev)) {
dev_err(&instance->pdev->dev, "Failed to add host from %s %d\n",
__func__, __LINE__); return -ENODEV;
}
return 0;
}
/** * megasas_set_dma_mask - Set DMA mask for supported controllers * * @instance: Adapter soft state * Description: * * For Ventura, driver/FW will operate in 63bit DMA addresses. * * For invader- * By default, driver/FW will operate in 32bit DMA addresses * for consistent DMA mapping but if 32 bit consistent * DMA mask fails, driver will try with 63 bit consistent * mask provided FW is true 63bit DMA capable * * For older controllers(Thunderbolt and MFI based adapters)- * driver/FW will operate in 32 bit consistent DMA addresses.
*/ staticint
megasas_set_dma_mask(struct megasas_instance *instance)
{
u64 consistent_mask; struct pci_dev *pdev;
u32 scratch_pad_1;
if (IS_DMA64) { if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(63)) &&
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) goto fail_set_dma_mask;
if ((*pdev->dev.dma_mask == DMA_BIT_MASK(63)) &&
(dma_set_coherent_mask(&pdev->dev, consistent_mask) &&
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))) { /* * If 32 bit DMA mask fails, then try for 64 bit mask * for FW capable of handling 64 bit DMA.
*/
scratch_pad_1 = megasas_readl
(instance, &instance->reg_set->outbound_scratch_pad_1);
/** * megasas_alloc_ctrl_mem - Allocate per controller memory for core data * structures which are not common across MFI * adapters and fusion adapters. * For MFI based adapters, allocate producer and * consumer buffers. For fusion adapters, allocate * memory for fusion context. * @instance: Adapter soft state * return: 0 for SUCCESS
*/ staticint megasas_alloc_ctrl_mem(struct megasas_instance *instance)
{
instance->reply_map = kcalloc(nr_cpu_ids, sizeof(unsignedint),
GFP_KERNEL); if (!instance->reply_map) return -ENOMEM;
switch (instance->adapter_type) { case MFI_SERIES: if (megasas_alloc_mfi_ctrl_mem(instance)) return -ENOMEM; break; case AERO_SERIES: case VENTURA_SERIES: case THUNDERBOLT_SERIES: case INVADER_SERIES: if (megasas_alloc_fusion_context(instance)) return -ENOMEM; break;
}
return 0;
}
/* * megasas_free_ctrl_mem - Free fusion context for fusion adapters and * producer, consumer buffers for MFI adapters * * @instance - Adapter soft instance *
*/ staticinlinevoid megasas_free_ctrl_mem(struct megasas_instance *instance)
{
kfree(instance->reply_map); if (instance->adapter_type == MFI_SERIES) { if (instance->producer)
dma_free_coherent(&instance->pdev->dev, sizeof(u32),
instance->producer,
instance->producer_h); if (instance->consumer)
dma_free_coherent(&instance->pdev->dev, sizeof(u32),
instance->consumer,
instance->consumer_h);
} else {
megasas_free_fusion_context(instance);
}
}
/** * megasas_alloc_ctrl_dma_buffers - Allocate consistent DMA buffers during * driver load time * * @instance: Adapter soft instance * * @return: O for SUCCESS
*/ staticinline int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
{ struct pci_dev *pdev = instance->pdev; struct fusion_context *fusion = instance->ctrl_context;
switch (pdev->device) { case PCI_DEVICE_ID_LSI_AERO_10E0: case PCI_DEVICE_ID_LSI_AERO_10E3: case PCI_DEVICE_ID_LSI_AERO_10E4: case PCI_DEVICE_ID_LSI_AERO_10E7:
dev_err(&pdev->dev, "Adapter is in non secure mode\n"); return 1; case PCI_DEVICE_ID_LSI_AERO_10E1: case PCI_DEVICE_ID_LSI_AERO_10E5:
dev_info(&pdev->dev, "Adapter is in configurable secure mode\n"); break;
}
/* Reset MSI-X in the kdump kernel */ if (reset_devices) {
pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX); if (pos) {
pci_read_config_word(pdev, pos + PCI_MSIX_FLAGS,
&control); if (control & PCI_MSIX_FLAGS_ENABLE) {
dev_info(&pdev->dev, "resetting MSI-X\n");
pci_write_config_word(pdev,
pos + PCI_MSIX_FLAGS,
control &
~PCI_MSIX_FLAGS_ENABLE);
}
}
}
/* * PCI prepping: enable device set bus mastering and dma mask
*/
rval = pci_enable_device_mem(pdev);
/* * Initialize MFI Firmware
*/ if (megasas_init_fw(instance)) goto fail_init_mfi;
if (instance->requestorId) { if (instance->PlasmaFW111) {
instance->vf_affiliation_111 =
dma_alloc_coherent(&pdev->dev, sizeof(struct MR_LD_VF_AFFILIATION_111),
&instance->vf_affiliation_111_h,
GFP_KERNEL); if (!instance->vf_affiliation_111)
dev_warn(&pdev->dev, "Can't allocate " "memory for VF affiliation buffer\n");
} else {
instance->vf_affiliation =
dma_alloc_coherent(&pdev->dev,
(MAX_LOGICAL_DRIVES + 1) * sizeof(struct MR_LD_VF_AFFILIATION),
&instance->vf_affiliation_h,
GFP_KERNEL); if (!instance->vf_affiliation)
dev_warn(&pdev->dev, "Can't allocate " "memory for VF affiliation buffer\n");
}
}
/* * Store instance in PCI softstate
*/
pci_set_drvdata(pdev, instance);
/* * Add this controller to megasas_mgmt_info structure so that it * can be exported to management applications
*/
megasas_mgmt_info.count++;
megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = instance;
megasas_mgmt_info.max_index++;
/* * Register with SCSI mid-layer
*/ if (megasas_io_attach(instance)) goto fail_io_attach;
instance->unload = 0; /* * Trigger SCSI to scan our drives
*/ if (!instance->enable_fw_dev_list ||
(instance->host_device_list_buf->count > 0))
scsi_scan_host(host);
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) return;
cmd = megasas_get_cmd(instance);
if (!cmd) return;
if (instance->aen_cmd)
megasas_issue_blocked_abort_cmd(instance,
instance->aen_cmd, MFI_IO_TIMEOUT_SECS); if (instance->map_update_cmd)
megasas_issue_blocked_abort_cmd(instance,
instance->map_update_cmd, MFI_IO_TIMEOUT_SECS); if (instance->jbod_seq_cmd)
megasas_issue_blocked_abort_cmd(instance,
instance->jbod_seq_cmd, MFI_IO_TIMEOUT_SECS);
/* cancel the delayed work if this work still in queue */ if (instance->ev != NULL) { struct megasas_aen_event *ev = instance->ev;
cancel_delayed_work_sync(&ev->hotplug_work);
instance->ev = NULL;
}
skip_firing_dcmds: /* cancel the delayed work if this work still in queue*/ if (instance->ev != NULL) { struct megasas_aen_event *ev = instance->ev;
cancel_delayed_work_sync(&ev->hotplug_work);
instance->ev = NULL;
}
/* cancel all wait events */
wake_up_all(&instance->int_cmd_wait_q);
tasklet_kill(&instance->isr_tasklet);
/* * Take the instance off the instance array. Note that we will not * decrement the max_index. We let this array be sparse array
*/ for (i = 0; i < megasas_mgmt_info.max_index; i++) { if (megasas_mgmt_info.instance[i] == instance) {
megasas_mgmt_info.count--;
megasas_mgmt_info.instance[i] = NULL;
break;
}
}
instance->instancet->disable_intr(instance);
megasas_destroy_irqs(instance);
if (instance->msix_vectors)
pci_free_irq_vectors(instance->pdev);
if (instance->adapter_type >= VENTURA_SERIES) { for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i)
kfree(fusion->stream_detect_by_ld[i]);
kfree(fusion->stream_detect_by_ld);
fusion->stream_detect_by_ld = NULL;
}
if (instance->adapter_type != MFI_SERIES) {
megasas_release_fusion(instance);
pd_seq_map_sz =
struct_size_t(struct MR_PD_CFG_SEQ_NUM_SYNC,
seq, MAX_PHYSICAL_DEVICES); for (i = 0; i < 2 ; i++) { if (fusion->ld_map[i])
dma_free_coherent(&instance->pdev->dev,
fusion->max_map_sz,
fusion->ld_map[i],
fusion->ld_map_phys[i]); if (fusion->ld_drv_map[i]) { if (is_vmalloc_addr(fusion->ld_drv_map[i]))
vfree(fusion->ld_drv_map[i]); else
free_pages((ulong)fusion->ld_drv_map[i],
fusion->drv_map_pages);
}
if (instance->msix_vectors)
pci_free_irq_vectors(instance->pdev);
}
/* * megasas_mgmt_open - char node "open" entry point * @inode: char node inode * @filep: char node file
*/ staticint megasas_mgmt_open(struct inode *inode, struct file *filep)
{ /* * Allow only those users with admin rights
*/ if (!capable(CAP_SYS_ADMIN)) return -EACCES;
return 0;
}
/* * megasas_mgmt_fasync - Async notifier registration from applications * @fd: char node file descriptor number * @filep: char node file * @mode: notifier on/off * * This function adds the calling process to a driver global queue. When an * event occurs, SIGIO will be sent to all processes in this queue.
*/ staticint megasas_mgmt_fasync(int fd, struct file *filep, int mode)
{ int rc;
cmd = megasas_get_cmd(instance); if (!cmd) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get a cmd packet\n"); return -ENOMEM;
}
/* * User's IOCTL packet has 2 frames (maximum). Copy those two * frames into our cmd's frames. cmd->frame's context will get * overwritten when we copy from user's frames. So set that value * alone separately
*/
memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
cmd->frame->hdr.context = cpu_to_le32(cmd->index);
cmd->frame->hdr.pad_0 = 0;
/* * The management interface between applications and the fw uses * MFI frames. E.g, RAID configuration changes, LD property changes * etc are accomplishes through different kinds of MFI frames. The * driver needs to care only about substituting user buffers with * kernel buffers in SGLs. The location of SGL is embedded in the * struct iocpacket itself.
*/ if (instance->consistent_mask_64bit)
kern_sge64 = (struct megasas_sge64 *)
((unsignedlong)cmd->frame + ioc->sgl_off); else
kern_sge32 = (struct megasas_sge32 *)
((unsignedlong)cmd->frame + ioc->sgl_off);
/* * For each user buffer, create a mirror buffer and copy in
*/ for (i = 0; i < ioc->sge_count; i++) { if (!ioc->sgl[i].iov_len) continue;
kbuff_arr[i] = dma_alloc_coherent(&instance->pdev->dev,
ioc->sgl[i].iov_len,
&buf_handle, GFP_KERNEL); if (!kbuff_arr[i]) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to alloc " "kernel SGL buffer for IOCTL\n");
error = -ENOMEM; goto out;
}
/* * We don't change the dma_coherent_mask, so * dma_alloc_coherent only returns 32bit addresses
*/ if (instance->consistent_mask_64bit) {
kern_sge64[i].phys_addr = cpu_to_le64(buf_handle);
kern_sge64[i].length = cpu_to_le32(ioc->sgl[i].iov_len);
} else {
kern_sge32[i].phys_addr = cpu_to_le32(buf_handle);
kern_sge32[i].length = cpu_to_le32(ioc->sgl[i].iov_len);
}
/* * We created a kernel buffer corresponding to the * user buffer. Now copy in from the user buffer
*/ if (copy_from_user(kbuff_arr[i], ioc->sgl[i].iov_base,
(u32) (ioc->sgl[i].iov_len))) {
error = -EFAULT; goto out;
}
}
if (ioc->sense_len) { /* make sure the pointer is part of the frame */ if (ioc->sense_off >
(sizeof(union megasas_frame) - sizeof(__le64))) {
error = -EINVAL; goto out;
}
sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len,
&sense_handle, GFP_KERNEL); if (!sense) {
error = -ENOMEM; goto out;
}
/* always store 64 bits regardless of addressing */
sense_ptr = (void *)cmd->frame + ioc->sense_off;
put_unaligned_le64(sense_handle, sense_ptr);
}
/* * Set the sync_cmd flag so that the ISR knows not to complete this * cmd to the SCSI mid-layer
*/
cmd->sync_cmd = 1;
ret = megasas_issue_blocked_cmd(instance, cmd, 0); switch (ret) { case DCMD_INIT: case DCMD_BUSY:
cmd->sync_cmd = 0;
dev_err(&instance->pdev->dev, "return -EBUSY from %s %d cmd 0x%x opcode 0x%x cmd->cmd_status_drv 0x%x\n",
__func__, __LINE__, cmd->frame->hdr.cmd, opcode,
cmd->cmd_status_drv);
error = -EBUSY; goto out;
}
cmd->sync_cmd = 0;
if (instance->unload == 1) {
dev_info(&instance->pdev->dev, "Driver unload is in progress " "don't submit data to application\n"); goto out;
} /* * copy out the kernel buffers to user buffers
*/ for (i = 0; i < ioc->sge_count; i++) { if (copy_to_user(ioc->sgl[i].iov_base, kbuff_arr[i],
ioc->sgl[i].iov_len)) {
error = -EFAULT; goto out;
}
}
/* * copy out the sense
*/ if (ioc->sense_len) { void __user *uptr; /* * sense_ptr points to the location that has the user * sense buffer address
*/
sense_ptr = (void *)ioc->frame.raw + ioc->sense_off; if (in_compat_syscall())
uptr = compat_ptr(get_unaligned((compat_uptr_t *)
sense_ptr)); else
uptr = get_unaligned((void __user **)sense_ptr);
if (copy_to_user(uptr, sense, ioc->sense_len)) {
dev_err(&instance->pdev->dev, "Failed to copy out to user " "sense data\n");
error = -EFAULT; goto out;
}
}
/* * copy the status codes returned by the fw
*/ if (copy_to_user(&user_ioc->frame.hdr.cmd_status,
&cmd->frame->hdr.cmd_status, sizeof(u8))) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error copying out cmd_status\n");
error = -EFAULT;
}
out: if (sense) {
dma_free_coherent(&instance->pdev->dev, ioc->sense_len,
sense, sense_handle);
}
for (i = 0; i < ioc->sge_count; i++) { if (kbuff_arr[i]) { if (instance->consistent_mask_64bit)
dma_free_coherent(&instance->pdev->dev,
le32_to_cpu(kern_sge64[i].length),
kbuff_arr[i],
le64_to_cpu(kern_sge64[i].phys_addr)); else
dma_free_coherent(&instance->pdev->dev,
le32_to_cpu(kern_sge32[i].length),
kbuff_arr[i],
le32_to_cpu(kern_sge32[i].phys_addr));
kbuff_arr[i] = NULL;
}
}
/** * megasas_update_device_list - Update the PD and LD device list from FW * after an AEN event notification * @instance: Adapter soft state * @event_type: Indicates type of event (PD or LD event) * * @return: Success or failure * * Issue DCMDs to Firmware to update the internal device list in driver. * Based on the FW support, driver sends the HOST_DEVICE_LIST or combination * of PD_LIST/LD_LIST_QUERY DCMDs to get the device list.
*/ static int megasas_update_device_list(struct megasas_instance *instance, int event_type)
{ int dcmd_ret;
if (instance->enable_fw_dev_list) { return megasas_host_device_list_query(instance, false);
} else { if (event_type & SCAN_PD_CHANNEL) {
dcmd_ret = megasas_get_pd_list(instance); if (dcmd_ret != DCMD_SUCCESS) return dcmd_ret;
}
if (event_type & SCAN_VD_CHANNEL) { if (!instance->requestorId ||
megasas_get_ld_vf_affiliation(instance, 0)) { return megasas_ld_list_query(instance,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
}
}
} return DCMD_SUCCESS;
}
/** * megasas_add_remove_devices - Add/remove devices to SCSI mid-layer * after an AEN event notification * @instance: Adapter soft state * @scan_type: Indicates type of devices (PD/LD) to add * @return void
*/ static void megasas_add_remove_devices(struct megasas_instance *instance, int scan_type)
{ int i, j;
u16 pd_index = 0;
u16 ld_index = 0;
u16 channel = 0, id = 0; struct Scsi_Host *host; struct scsi_device *sdev1; struct MR_HOST_DEVICE_LIST *targetid_list = NULL; struct MR_HOST_DEVICE_LIST_ENTRY *targetid_entry = NULL;
host = instance->host;
if (instance->enable_fw_dev_list) {
targetid_list = instance->host_device_list_buf; for (i = 0; i < targetid_list->count; i++) {
targetid_entry = &targetid_list->host_device_list[i]; if (targetid_entry->flags.u.bits.is_sys_pd) {
channel = le16_to_cpu(targetid_entry->target_id) /
MEGASAS_MAX_DEV_PER_CHANNEL;
id = le16_to_cpu(targetid_entry->target_id) %
MEGASAS_MAX_DEV_PER_CHANNEL;
} else {
channel = MEGASAS_MAX_PD_CHANNELS +
(le16_to_cpu(targetid_entry->target_id) /
MEGASAS_MAX_DEV_PER_CHANNEL);
id = le16_to_cpu(targetid_entry->target_id) %
MEGASAS_MAX_DEV_PER_CHANNEL;
}
sdev1 = scsi_device_lookup(host, channel, id, 0); if (!sdev1) {
scsi_add_device(host, channel, id, 0);
} else {
scsi_device_put(sdev1);
}
}
}
if (scan_type & SCAN_PD_CHANNEL) { for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) { for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
pd_index = i * MEGASAS_MAX_DEV_PER_CHANNEL + j;
sdev1 = scsi_device_lookup(host, i, j, 0); if (instance->pd_list[pd_index].driveState ==
MR_PD_STATE_SYSTEM) { if (!sdev1)
scsi_add_device(host, i, j, 0); else
scsi_device_put(sdev1);
} else { if (sdev1)
megasas_remove_scsi_device(sdev1);
}
}
}
}
if (scan_type & SCAN_VD_CHANNEL) { for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) { for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
ld_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
sdev1 = scsi_device_lookup(host,
MEGASAS_MAX_PD_CHANNELS + i, j, 0); if (instance->ld_ids[ld_index] != 0xff) { if (!sdev1)
scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0); else
scsi_device_put(sdev1);
} else { if (sdev1)
megasas_remove_scsi_device(sdev1);
}
}
}
}
case MR_EVT_PD_INSERTED: case MR_EVT_PD_REMOVED:
event_type = SCAN_PD_CHANNEL; break;
case MR_EVT_LD_OFFLINE: case MR_EVT_LD_DELETED:
ld_target_id = instance->evt_detail->args.ld.target_id;
sdev1 = scsi_device_lookup(instance->host,
MEGASAS_MAX_PD_CHANNELS +
(ld_target_id / MEGASAS_MAX_DEV_PER_CHANNEL),
(ld_target_id % MEGASAS_MAX_DEV_PER_CHANNEL),
0); if (sdev1) {
mutex_unlock(&instance->reset_mutex);
megasas_remove_scsi_device(sdev1);
mutex_lock(&instance->reset_mutex);
}
event_type = SCAN_VD_CHANNEL; break; case MR_EVT_LD_CREATED:
event_type = SCAN_VD_CHANNEL; break;
case MR_EVT_CFG_CLEARED: case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED: case MR_EVT_FOREIGN_CFG_IMPORTED: case MR_EVT_LD_STATE_CHANGE:
event_type = SCAN_PD_CHANNEL | SCAN_VD_CHANNEL;
dev_info(&instance->pdev->dev, "scanning for scsi%d...\n",
instance->host->host_no); break;
if ((event_log_level < MFI_EVT_CLASS_DEBUG) ||
(event_log_level > MFI_EVT_CLASS_DEAD)) {
pr_warn("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;
}
rval = driver_create_file(&megasas_pci_driver.driver,
&driver_attr_version); if (rval) goto err_dcf_attr_ver;
rval = driver_create_file(&megasas_pci_driver.driver,
&driver_attr_release_date); if (rval) goto err_dcf_rel_date;
rval = driver_create_file(&megasas_pci_driver.driver,
&driver_attr_support_poll_for_event); if (rval) goto err_dcf_support_poll_for_event;
rval = driver_create_file(&megasas_pci_driver.driver,
&driver_attr_dbg_lvl); if (rval) goto err_dcf_dbg_lvl;
rval = driver_create_file(&megasas_pci_driver.driver,
&driver_attr_support_device_change); if (rval) goto err_dcf_support_device_change;
rval = driver_create_file(&megasas_pci_driver.driver,
&driver_attr_support_nvme_encapsulation); if (rval) goto err_dcf_support_nvme_encapsulation;
rval = driver_create_file(&megasas_pci_driver.driver,
&driver_attr_support_pci_lane_margining); if (rval) goto err_dcf_support_pci_lane_margining;