aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/megaraid/megaraid_sas.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/megaraid/megaraid_sas.c')
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c366
1 files changed, 278 insertions, 88 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 4cab5b534b2..977b6e8d852 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_sas.c
- * Version : v00.00.03.01
+ * Version : v00.00.03.05
*
* Authors:
* Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
@@ -71,6 +71,8 @@ static struct megasas_mgmt_info megasas_mgmt_info;
static struct fasync_struct *megasas_async_queue;
static DEFINE_MUTEX(megasas_async_queue_mutex);
+static u32 megasas_dbg_lvl;
+
/**
* megasas_get_cmd - Get a command from the free pool
* @instance: Adapter soft state
@@ -135,6 +137,19 @@ megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs)
}
/**
+ * megasas_disable_intr_xscale -Disables interrupt
+ * @regs: MFI register set
+ */
+static inline void
+megasas_disable_intr_xscale(struct megasas_register_set __iomem * regs)
+{
+ u32 mask = 0x1f;
+ writel(mask, &regs->outbound_intr_mask);
+ /* Dummy readl to force pci flush */
+ readl(&regs->outbound_intr_mask);
+}
+
+/**
* megasas_read_fw_status_reg_xscale - returns the current FW status value
* @regs: MFI register set
*/
@@ -185,6 +200,7 @@ static struct megasas_instance_template megasas_instance_template_xscale = {
.fire_cmd = megasas_fire_cmd_xscale,
.enable_intr = megasas_enable_intr_xscale,
+ .disable_intr = megasas_disable_intr_xscale,
.clear_intr = megasas_clear_intr_xscale,
.read_fw_status_reg = megasas_read_fw_status_reg_xscale,
};
@@ -215,6 +231,19 @@ megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs)
}
/**
+ * megasas_disable_intr_ppc - Disable interrupt
+ * @regs: MFI register set
+ */
+static inline void
+megasas_disable_intr_ppc(struct megasas_register_set __iomem * regs)
+{
+ u32 mask = 0xFFFFFFFF;
+ writel(mask, &regs->outbound_intr_mask);
+ /* Dummy readl to force pci flush */
+ readl(&regs->outbound_intr_mask);
+}
+
+/**
* megasas_read_fw_status_reg_ppc - returns the current FW status value
* @regs: MFI register set
*/
@@ -265,6 +294,7 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
.fire_cmd = megasas_fire_cmd_ppc,
.enable_intr = megasas_enable_intr_ppc,
+ .disable_intr = megasas_disable_intr_ppc,
.clear_intr = megasas_clear_intr_ppc,
.read_fw_status_reg = megasas_read_fw_status_reg_ppc,
};
@@ -275,25 +305,6 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
*/
/**
- * megasas_disable_intr - Disables interrupts
- * @regs: MFI register set
- */
-static inline void
-megasas_disable_intr(struct megasas_instance *instance)
-{
- u32 mask = 0x1f;
- struct megasas_register_set __iomem *regs = instance->reg_set;
-
- if(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078R)
- mask = 0xffffffff;
-
- writel(mask, &regs->outbound_intr_mask);
-
- /* Dummy readl to force pci flush */
- readl(&regs->outbound_intr_mask);
-}
-
-/**
* megasas_issue_polled - Issues a polling command
* @instance: Adapter soft state
* @cmd: Command packet to be issued
@@ -336,6 +347,7 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
* @cmd: Command to be issued
*
* 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.
*/
static int
@@ -346,7 +358,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
- wait_event(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA));
+ wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
+ MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
return 0;
}
@@ -358,7 +371,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
*
* MFI firmware can abort previously issued AEN comamnd (automatic event
* notification). The megasas_issue_blocked_abort_cmd() issues such abort
- * cmd and blocks till it is completed.
+ * cmd and waits for return status.
+ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
*/
static int
megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
@@ -392,7 +406,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
/*
* Wait for this cmd to complete
*/
- wait_event(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF));
+ wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF),
+ MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
megasas_return_cmd(instance, cmd);
return 0;
@@ -495,6 +510,46 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
return sge_count;
}
+ /**
+ * megasas_get_frame_count - Computes the number of frames
+ * @sge_count : number of sg elements
+ *
+ * Returns the number of frames required for numnber of sge's (sge_count)
+ */
+
+u32 megasas_get_frame_count(u8 sge_count)
+{
+ int num_cnt;
+ int sge_bytes;
+ u32 sge_sz;
+ u32 frame_count=0;
+
+ sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
+ sizeof(struct megasas_sge32);
+
+ /*
+ * Main frame can contain 2 SGEs for 64-bit SGLs and
+ * 3 SGEs for 32-bit SGLs
+ */
+ if (IS_DMA64)
+ num_cnt = sge_count - 2;
+ else
+ num_cnt = sge_count - 3;
+
+ if(num_cnt>0){
+ sge_bytes = sge_sz * num_cnt;
+
+ frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
+ ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ;
+ }
+ /* Main frame */
+ frame_count +=1;
+
+ if (frame_count > 7)
+ frame_count = 8;
+ return frame_count;
+}
+
/**
* megasas_build_dcdb - Prepares a direct cdb (DCDB) command
* @instance: Adapter soft state
@@ -508,8 +563,6 @@ static int
megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
struct megasas_cmd *cmd)
{
- u32 sge_sz;
- int sge_bytes;
u32 is_logical;
u32 device_id;
u16 flags = 0;
@@ -544,9 +597,6 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
/*
* Construct SGL
*/
- sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
- sizeof(struct megasas_sge32);
-
if (IS_DMA64) {
pthru->flags |= MFI_FRAME_SGL64;
pthru->sge_count = megasas_make_sgl64(instance, scp,
@@ -562,17 +612,11 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
pthru->sense_buf_phys_addr_hi = 0;
pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
- sge_bytes = sge_sz * pthru->sge_count;
-
/*
* 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 = (sge_bytes / MEGAMFI_FRAME_SIZE) +
- ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
-
- if (cmd->frame_count > 7)
- cmd->frame_count = 8;
+ cmd->frame_count = megasas_get_frame_count(pthru->sge_count);
return cmd->frame_count;
}
@@ -589,8 +633,6 @@ static int
megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
struct megasas_cmd *cmd)
{
- u32 sge_sz;
- int sge_bytes;
u32 device_id;
u8 sc = scp->cmnd[0];
u16 flags = 0;
@@ -605,7 +647,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
flags = MFI_FRAME_DIR_READ;
/*
- * Preare the Logical IO frame: 2nd bit is zero for all read cmds
+ * Prepare the Logical IO frame: 2nd bit is zero for all read cmds
*/
ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ;
ldio->cmd_status = 0x0;
@@ -674,9 +716,6 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
/*
* Construct SGL
*/
- sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
- sizeof(struct megasas_sge32);
-
if (IS_DMA64) {
ldio->flags |= MFI_FRAME_SGL64;
ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
@@ -690,13 +729,11 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
ldio->sense_buf_phys_addr_hi = 0;
ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
- sge_bytes = sge_sz * ldio->sge_count;
-
- cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
- ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
-
- if (cmd->frame_count > 7)
- cmd->frame_count = 8;
+ /*
+ * 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(ldio->sge_count);
return cmd->frame_count;
}
@@ -727,6 +764,69 @@ static inline int megasas_is_ldio(struct scsi_cmnd *cmd)
}
}
+ /**
+ * megasas_dump_pending_frames - Dumps the frame address of all pending cmds
+ * in FW
+ * @instance: Adapter soft state
+ */
+static inline void
+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;
+ u32 max_cmd = instance->max_fw_cmds;
+
+ printk(KERN_ERR "\nmegasas[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);
+ printk(KERN_ERR "megasas[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding));
+ if (IS_DMA64)
+ printk(KERN_ERR "\nmegasas[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no);
+ else
+ printk(KERN_ERR "\nmegasas[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no);
+
+ printk(KERN_ERR "megasas[%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;
+ printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr);
+ if (megasas_is_ldio(cmd->scmd)){
+ ldio = (struct megasas_io_frame *)cmd->frame;
+ mfi_sgl = &ldio->sgl;
+ sgcount = ldio->sge_count;
+ printk(KERN_ERR "megasas[%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, ldio->start_lba_lo,ldio->start_lba_hi,ldio->sense_buf_phys_addr_lo,sgcount);
+ }
+ else {
+ pthru = (struct megasas_pthru_frame *) cmd->frame;
+ mfi_sgl = &pthru->sgl;
+ sgcount = pthru->sge_count;
+ printk(KERN_ERR "megasas[%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 , pthru->data_xfer_len,pthru->sense_buf_phys_addr_lo,sgcount);
+ }
+ if(megasas_dbg_lvl & MEGASAS_DBG_LVL){
+ for (n = 0; n < sgcount; n++){
+ if (IS_DMA64)
+ printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%08lx ",mfi_sgl->sge64[n].length , (unsigned long)mfi_sgl->sge64[n].phys_addr) ;
+ else
+ printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",mfi_sgl->sge32[n].length , mfi_sgl->sge32[n].phys_addr) ;
+ }
+ }
+ printk(KERN_ERR "\n");
+ } /*for max_cmd*/
+ printk(KERN_ERR "\nmegasas[%d]: Pending Internal cmds in FW : \n",instance->host->host_no);
+ for (i = 0; i < max_cmd; i++) {
+
+ cmd = instance->cmd_list[i];
+
+ if(cmd->sync_cmd == 1){
+ printk(KERN_ERR "0x%08lx : ", (unsigned long)cmd->frame_phys_addr);
+ }
+ }
+ printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no);
+}
+
/**
* megasas_queue_command - Queue entry point
* @scmd: SCSI command to be queued
@@ -832,6 +932,13 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
}
if (atomic_read(&instance->fw_outstanding)) {
+ /*
+ * Send signal to FW to stop processing any pending cmds.
+ * The controller will be taken offline by the OS now.
+ */
+ writel(MFI_STOP_ADP,
+ &instance->reg_set->inbound_doorbell);
+ megasas_dump_pending_frames(instance);
instance->hw_crit_error = 1;
return FAILED;
}
@@ -1168,11 +1275,6 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
static int
megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
{
- u32 producer;
- u32 consumer;
- u32 context;
- struct megasas_cmd *cmd;
-
/*
* Check if it is our interrupt
* Clear the interrupt
@@ -1180,23 +1282,10 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
if(instance->instancet->clear_intr(instance->reg_set))
return IRQ_NONE;
- producer = *instance->producer;
- consumer = *instance->consumer;
-
- while (consumer != producer) {
- context = instance->reply_queue[consumer];
-
- cmd = instance->cmd_list[context];
-
- megasas_complete_cmd(instance, cmd, alt_status);
-
- consumer++;
- if (consumer == (instance->max_fw_cmds + 1)) {
- consumer = 0;
- }
- }
-
- *instance->consumer = producer;
+ /*
+ * Schedule the tasklet for cmd completion
+ */
+ tasklet_schedule(&instance->isr_tasklet);
return IRQ_HANDLED;
}
@@ -1229,10 +1318,12 @@ megasas_transition_to_ready(struct megasas_instance* instance)
fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+ if (fw_state != MFI_STATE_READY)
+ printk(KERN_INFO "megasas: Waiting for FW to come to ready"
+ " state\n");
+
while (fw_state != MFI_STATE_READY) {
- printk(KERN_INFO "megasas: Waiting for FW to come to ready"
- " state\n");
switch (fw_state) {
case MFI_STATE_FAULT:
@@ -1244,19 +1335,27 @@ megasas_transition_to_ready(struct megasas_instance* instance)
/*
* Set the CLR bit in inbound doorbell
*/
- writel(MFI_INIT_CLEAR_HANDSHAKE,
+ writel(MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
&instance->reg_set->inbound_doorbell);
max_wait = 2;
cur_state = MFI_STATE_WAIT_HANDSHAKE;
break;
+ case MFI_STATE_BOOT_MESSAGE_PENDING:
+ writel(MFI_INIT_HOTPLUG,
+ &instance->reg_set->inbound_doorbell);
+
+ max_wait = 10;
+ cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
+ break;
+
case MFI_STATE_OPERATIONAL:
/*
- * Bring it to READY state; assuming max wait 2 secs
+ * Bring it to READY state; assuming max wait 10 secs
*/
- megasas_disable_intr(instance);
- writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell);
+ instance->instancet->disable_intr(instance->reg_set);
+ writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell);
max_wait = 10;
cur_state = MFI_STATE_OPERATIONAL;
@@ -1323,6 +1422,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
return -ENODEV;
}
};
+ printk(KERN_INFO "megasas: FW now in Ready state\n");
return 0;
}
@@ -1352,7 +1452,7 @@ static void megasas_teardown_frame_pool(struct megasas_instance *instance)
cmd->frame_phys_addr);
if (cmd->sense)
- pci_pool_free(instance->sense_dma_pool, cmd->frame,
+ pci_pool_free(instance->sense_dma_pool, cmd->sense,
cmd->sense_phys_addr);
}
@@ -1628,6 +1728,39 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
}
/**
+ * megasas_complete_cmd_dpc - Returns FW's controller structure
+ * @instance_addr: Address of adapter soft state
+ *
+ * Tasklet to complete cmds
+ */
+void megasas_complete_cmd_dpc(unsigned long instance_addr)
+{
+ u32 producer;
+ u32 consumer;
+ u32 context;
+ struct megasas_cmd *cmd;
+ struct megasas_instance *instance = (struct megasas_instance *)instance_addr;
+
+ producer = *instance->producer;
+ consumer = *instance->consumer;
+
+ while (consumer != producer) {
+ context = instance->reply_queue[consumer];
+
+ cmd = instance->cmd_list[context];
+
+ megasas_complete_cmd(instance, cmd, DID_OK);
+
+ consumer++;
+ if (consumer == (instance->max_fw_cmds + 1)) {
+ consumer = 0;
+ }
+ }
+
+ *instance->consumer = producer;
+}
+
+/**
* megasas_init_mfi - Initializes the FW
* @instance: Adapter soft state
*
@@ -1690,6 +1823,12 @@ static int megasas_init_mfi(struct megasas_instance *instance)
* Get various operational parameters from status register
*/
instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 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_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
0x10;
/*
@@ -1754,7 +1893,7 @@ static int megasas_init_mfi(struct megasas_instance *instance)
/*
* disable the intr before firing the init frame to FW
*/
- megasas_disable_intr(instance);
+ instance->instancet->disable_intr(instance->reg_set);
/*
* Issue the init frame in polled mode
@@ -1791,6 +1930,12 @@ static int megasas_init_mfi(struct megasas_instance *instance)
kfree(ctrl_info);
+ /*
+ * Setup tasklet for cmd completion
+ */
+
+ tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+ (unsigned long)instance);
return 0;
fail_fw_init:
@@ -2182,6 +2327,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
instance->init_id = MEGASAS_DEFAULT_INIT_ID;
+ megasas_dbg_lvl = 0;
+
/*
* Initialize MFI Firmware
*/
@@ -2234,7 +2381,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
megasas_mgmt_info.max_index--;
pci_set_drvdata(pdev, NULL);
- megasas_disable_intr(instance);
+ instance->instancet->disable_intr(instance->reg_set);
free_irq(instance->pdev->irq, instance);
megasas_release_mfi(instance);
@@ -2348,6 +2495,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
scsi_remove_host(instance->host);
megasas_flush_cache(instance);
megasas_shutdown_controller(instance);
+ tasklet_kill(&instance->isr_tasklet);
/*
* Take the instance off the instance array. Note that we will not
@@ -2364,7 +2512,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
pci_set_drvdata(instance->pdev, NULL);
- megasas_disable_intr(instance);
+ instance->instancet->disable_intr(instance->reg_set);
free_irq(instance->pdev->irq, instance);
@@ -2716,7 +2864,8 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
int i;
int error = 0;
- clear_user(ioc, sizeof(*ioc));
+ if (clear_user(ioc, sizeof(*ioc)))
+ return -EFAULT;
if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) ||
copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) ||
@@ -2808,6 +2957,26 @@ megasas_sysfs_show_release_date(struct device_driver *dd, char *buf)
static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
NULL);
+static ssize_t
+megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
+{
+ return sprintf(buf,"%u",megasas_dbg_lvl);
+}
+
+static ssize_t
+megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t count)
+{
+ int retval = count;
+ if(sscanf(buf,"%u",&megasas_dbg_lvl)<1){
+ printk(KERN_ERR "megasas: could not set dbg_lvl\n");
+ retval = -EINVAL;
+ }
+ return retval;
+}
+
+static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl,
+ megasas_sysfs_set_dbg_lvl);
+
/**
* megasas_init - Driver load entry point
*/
@@ -2842,14 +3011,33 @@ static int __init megasas_init(void)
if (rval) {
printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n");
- unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
- }
-
- driver_create_file(&megasas_pci_driver.driver, &driver_attr_version);
- driver_create_file(&megasas_pci_driver.driver,
- &driver_attr_release_date);
+ goto err_pcidrv;
+ }
+
+ 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_dbg_lvl);
+ if (rval)
+ goto err_dcf_dbg_lvl;
return rval;
+err_dcf_dbg_lvl:
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_release_date);
+err_dcf_rel_date:
+ driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+err_dcf_attr_ver:
+ pci_unregister_driver(&megasas_pci_driver);
+err_pcidrv:
+ unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
+ return rval;
}
/**
@@ -2857,9 +3045,11 @@ static int __init megasas_init(void)
*/
static void __exit megasas_exit(void)
{
- driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_dbg_lvl);
driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_release_date);
+ driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
pci_unregister_driver(&megasas_pci_driver);
unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");