]> Pileus Git - ~andy/linux/blobdiff - drivers/message/fusion/mptbase.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[~andy/linux] / drivers / message / fusion / mptbase.c
index c6be6eba7dc360d82c63e0892d5da4008742f906..75e599b85b645aba6d4de501f7f6c22e01dfa825 100644 (file)
@@ -5,7 +5,7 @@
  *      For use with LSI PCI chip/adapter(s)
  *      running LSI Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 1999-2007 LSI Corporation
+ *  Copyright (c) 1999-2008 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  */
@@ -79,7 +79,7 @@ MODULE_VERSION(my_VERSION);
 /*
  *  cmd line parameters
  */
-static int mpt_msi_enable;
+static int mpt_msi_enable = -1;
 module_param(mpt_msi_enable, int, 0);
 MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
 
@@ -103,7 +103,7 @@ static int mfcounter = 0;
  *  Public data...
  */
 
-struct proc_dir_entry *mpt_proc_root_dir;
+static struct proc_dir_entry *mpt_proc_root_dir;
 
 #define WHOINIT_UNKNOWN                0xAA
 
@@ -253,6 +253,55 @@ mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
        return 0;
 }
 
+/**
+ *     mpt_fault_reset_work - work performed on workq after ioc fault
+ *     @work: input argument, used to derive ioc
+ *
+**/
+static void
+mpt_fault_reset_work(struct work_struct *work)
+{
+       MPT_ADAPTER     *ioc =
+           container_of(work, MPT_ADAPTER, fault_reset_work.work);
+       u32              ioc_raw_state;
+       int              rc;
+       unsigned long    flags;
+
+       if (ioc->diagPending || !ioc->active)
+               goto out;
+
+       ioc_raw_state = mpt_GetIocState(ioc, 0);
+       if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
+               printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
+                   ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
+               printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
+                   ioc->name, __FUNCTION__);
+               rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
+               printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
+                   __FUNCTION__, (rc == 0) ? "success" : "failed");
+               ioc_raw_state = mpt_GetIocState(ioc, 0);
+               if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
+                       printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
+                           "reset (%04xh)\n", ioc->name, ioc_raw_state &
+                           MPI_DOORBELL_DATA_MASK);
+       }
+
+ out:
+       /*
+        * Take turns polling alternate controller
+        */
+       if (ioc->alt_ioc)
+               ioc = ioc->alt_ioc;
+
+       /* rearm the timer */
+       spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
+       if (ioc->reset_work_q)
+               queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
+                       msecs_to_jiffies(MPT_POLLING_INTERVAL));
+       spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
+}
+
+
 /*
  *  Process turbo (context) reply...
  */
@@ -1616,6 +1665,22 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        /* Find lookup slot. */
        INIT_LIST_HEAD(&ioc->list);
 
+
+       /* Initialize workqueue */
+       INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
+       spin_lock_init(&ioc->fault_reset_work_lock);
+
+       snprintf(ioc->reset_work_q_name, KOBJ_NAME_LEN, "mpt_poll_%d", ioc->id);
+       ioc->reset_work_q =
+               create_singlethread_workqueue(ioc->reset_work_q_name);
+       if (!ioc->reset_work_q) {
+               printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
+                   ioc->name);
+               pci_release_selected_regions(pdev, ioc->bars);
+               kfree(ioc);
+               return -ENOMEM;
+       }
+
        dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
            ioc->name, &ioc->facts, &ioc->pfacts[0]));
 
@@ -1686,6 +1751,16 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
                ioc->bus_type = SAS;
        }
 
+       if (mpt_msi_enable == -1) {
+               /* Enable on SAS, disable on FC and SPI */
+               if (ioc->bus_type == SAS)
+                       ioc->msi_enable = 1;
+               else
+                       ioc->msi_enable = 0;
+       } else
+               /* follow flag: 0 - disable; 1 - enable */
+               ioc->msi_enable = mpt_msi_enable;
+
        if (ioc->errata_flag_1064)
                pci_disable_io_access(pdev);
 
@@ -1717,6 +1792,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
                iounmap(ioc->memmap);
                if (r != -5)
                        pci_release_selected_regions(pdev, ioc->bars);
+
+               destroy_workqueue(ioc->reset_work_q);
+               ioc->reset_work_q = NULL;
+
                kfree(ioc);
                pci_set_drvdata(pdev, NULL);
                return r;
@@ -1749,6 +1828,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 #endif
 
+       if (!ioc->alt_ioc)
+               queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
+                       msecs_to_jiffies(MPT_POLLING_INTERVAL));
+
        return 0;
 }
 
@@ -1764,6 +1847,19 @@ mpt_detach(struct pci_dev *pdev)
        MPT_ADAPTER     *ioc = pci_get_drvdata(pdev);
        char pname[32];
        u8 cb_idx;
+       unsigned long flags;
+       struct workqueue_struct *wq;
+
+       /*
+        * Stop polling ioc for fault condition
+        */
+       spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
+       wq = ioc->reset_work_q;
+       ioc->reset_work_q = NULL;
+       spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
+       cancel_delayed_work(&ioc->fault_reset_work);
+       destroy_workqueue(wq);
+
 
        sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
        remove_proc_entry(pname, NULL);
@@ -1831,7 +1927,7 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state)
        CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
        free_irq(ioc->pci_irq, ioc);
-       if (mpt_msi_enable)
+       if (ioc->msi_enable)
                pci_disable_msi(ioc->pcidev);
        ioc->pci_irq = -1;
        pci_save_state(pdev);
@@ -2057,15 +2153,17 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
        if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
                ioc->pci_irq = -1;
                if (ioc->pcidev->irq) {
-                       if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
+                       if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
                                printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
                                    ioc->name);
+                       else
+                               ioc->msi_enable = 0;
                        rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
                            IRQF_SHARED, ioc->name, ioc);
                        if (rc < 0) {
                                printk(MYIOC_s_ERR_FMT "Unable to allocate "
                                    "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
-                               if (mpt_msi_enable)
+                               if (ioc->msi_enable)
                                        pci_disable_msi(ioc->pcidev);
                                return -EBUSY;
                        }
@@ -2173,7 +2271,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                /*
                 * Initalize link list for inactive raid volumes.
                 */
-               init_MUTEX(&ioc->raid_data.inactive_list_mutex);
+               mutex_init(&ioc->raid_data.inactive_list_mutex);
                INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
 
                if (ioc->bus_type == SAS) {
@@ -2261,7 +2359,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
  out:
        if ((ret != 0) && irq_allocated) {
                free_irq(ioc->pci_irq, ioc);
-               if (mpt_msi_enable)
+               if (ioc->msi_enable)
                        pci_disable_msi(ioc->pcidev);
        }
        return ret;
@@ -2443,7 +2541,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
 
        if (ioc->pci_irq != -1) {
                free_irq(ioc->pci_irq, ioc);
-               if (mpt_msi_enable)
+               if (ioc->msi_enable)
                        pci_disable_msi(ioc->pcidev);
                ioc->pci_irq = -1;
        }
@@ -5159,13 +5257,13 @@ mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
        if (list_empty(&ioc->raid_data.inactive_list))
                return;
 
-       down(&ioc->raid_data.inactive_list_mutex);
+       mutex_lock(&ioc->raid_data.inactive_list_mutex);
        list_for_each_entry_safe(component_info, pNext,
            &ioc->raid_data.inactive_list, list) {
                list_del(&component_info->list);
                kfree(component_info);
        }
-       up(&ioc->raid_data.inactive_list_mutex);
+       mutex_unlock(&ioc->raid_data.inactive_list_mutex);
 }
 
 /**
@@ -5224,7 +5322,7 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
        if (!handle_inactive_volumes)
                goto out;
 
-       down(&ioc->raid_data.inactive_list_mutex);
+       mutex_lock(&ioc->raid_data.inactive_list_mutex);
        for (i = 0; i < buffer->NumPhysDisks; i++) {
                if(mpt_raid_phys_disk_pg0(ioc,
                    buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
@@ -5244,7 +5342,7 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
                list_add_tail(&component_info->list,
                    &ioc->raid_data.inactive_list);
        }
-       up(&ioc->raid_data.inactive_list_mutex);
+       mutex_unlock(&ioc->raid_data.inactive_list_mutex);
 
  out:
        if (buffer)
@@ -7444,7 +7542,6 @@ EXPORT_SYMBOL(mpt_resume);
 EXPORT_SYMBOL(mpt_suspend);
 #endif
 EXPORT_SYMBOL(ioc_list);
-EXPORT_SYMBOL(mpt_proc_root_dir);
 EXPORT_SYMBOL(mpt_register);
 EXPORT_SYMBOL(mpt_deregister);
 EXPORT_SYMBOL(mpt_event_register);