[PATCH] mark struct file_operations const 6
[safe/jmp/linux-2.6] / drivers / scsi / megaraid / megaraid_sas.c
index c3b50b3..15e24fc 100644 (file)
  *        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>
- *     Sumant Patro            <Sumant.Patro@lsil.com>
+ *     Sreenivas Bagalkote     <Sreenivas.Bagalkote@lsi.com>
+ *     Sumant Patro            <Sumant.Patro@lsi.com>
  *
  * List of supported controllers
  *
@@ -45,7 +45,7 @@
 
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
-MODULE_AUTHOR("sreenivas.bagalkote@lsil.com");
+MODULE_AUTHOR("megaraidlinux@lsi.com");
 MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver");
 
 /*
@@ -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
@@ -345,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
@@ -355,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;
 }
@@ -367,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,
@@ -401,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;
@@ -511,7 +517,7 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
  * Returns the number of frames required for numnber of sge's (sge_count)
  */
 
-u32 megasas_get_frame_count(u8 sge_count)
+static u32 megasas_get_frame_count(u8 sge_count)
 {
        int num_cnt;
        int sge_bytes;
@@ -758,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
@@ -869,6 +938,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
                */
                writel(MFI_STOP_ADP,
                                &instance->reg_set->inbound_doorbell);
+               megasas_dump_pending_frames(instance);
                instance->hw_crit_error = 1;
                return FAILED;
        }
@@ -1205,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 
@@ -1217,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;
 }
@@ -1241,7 +1293,7 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
 /**
  * megasas_isr - isr entry point
  */
-static irqreturn_t megasas_isr(int irq, void *devp, struct pt_regs *regs)
+static irqreturn_t megasas_isr(int irq, void *devp)
 {
        return megasas_deplete_reply_queue((struct megasas_instance *)devp,
                                           DID_OK);
@@ -1676,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
+ */
+static 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
  *
@@ -1845,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:
@@ -2236,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
         */
@@ -2402,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
@@ -2770,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)) ||
@@ -2818,7 +2913,7 @@ megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd,
 /*
  * File operations structure for management interface
  */
-static struct file_operations megasas_mgmt_fops = {
+static const struct file_operations megasas_mgmt_fops = {
        .owner = THIS_MODULE,
        .open = megasas_mgmt_open,
        .release = megasas_mgmt_release,
@@ -2862,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
  */
@@ -2896,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;
 }
 
 /**
@@ -2911,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");