[SCSI] mvsas: fix 94xx hotplug issue
[pandora-kernel.git] / drivers / scsi / mvsas / mv_init.c
index 938d045..b111ae2 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright 2007 Red Hat, Inc.
  * Copyright 2008 Marvell. <kewei@marvell.com>
+ * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
  *
  * This file is licensed under GPLv2.
  *
 
 #include "mv_sas.h"
 
+static int lldd_max_execute_num = 1;
+module_param_named(collector, lldd_max_execute_num, int, S_IRUGO);
+MODULE_PARM_DESC(collector, "\n"
+       "\tIf greater than one, tells the SAS Layer to run in Task Collector\n"
+       "\tMode.  If 1 or 0, tells the SAS Layer to run in Direct Mode.\n"
+       "\tThe mvsas SAS LLDD supports both modes.\n"
+       "\tDefault: 1 (Direct Mode).\n");
+
+int interrupt_coalescing = 0x80;
+
 static struct scsi_transport_template *mvs_stt;
+struct kmem_cache *mvs_task_list_cache;
 static const struct mvs_chip_info mvs_chips[] = {
        [chip_6320] =   { 1, 2, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
        [chip_6440] =   { 1, 4, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
        [chip_6485] =   { 1, 8, 0x800, 33, 32, 10, &mvs_64xx_dispatch, },
        [chip_9180] =   { 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
        [chip_9480] =   { 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
+       [chip_9445] =   { 1, 4, 0x800, 17, 64, 11, &mvs_94xx_dispatch, },
+       [chip_9485] =   { 2, 4, 0x800, 17, 64, 11, &mvs_94xx_dispatch, },
        [chip_1300] =   { 1, 4, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
        [chip_1320] =   { 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
 };
 
+struct device_attribute *mvst_host_attrs[];
+
 #define SOC_SAS_NUM 2
 #define SG_MX 64
 
@@ -62,6 +78,7 @@ static struct scsi_host_template mvs_sht = {
        .slave_alloc            = mvs_slave_alloc,
        .target_destroy         = sas_target_destroy,
        .ioctl                  = sas_ioctl,
+       .shost_attrs            = mvst_host_attrs,
 };
 
 static struct sas_domain_function_template mvs_transport_ops = {
@@ -107,7 +124,6 @@ static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
 
 static void mvs_free(struct mvs_info *mvi)
 {
-       int i;
        struct mvs_wq *mwq;
        int slot_nr;
 
@@ -119,12 +135,8 @@ static void mvs_free(struct mvs_info *mvi)
        else
                slot_nr = MVS_SLOTS;
 
-       for (i = 0; i < mvi->tags_num; i++) {
-               struct mvs_slot_info *slot = &mvi->slot_info[i];
-               if (slot->buf)
-                       dma_free_coherent(mvi->dev, MVS_SLOT_BUF_SZ,
-                                         slot->buf, slot->buf_dma);
-       }
+       if (mvi->dma_pool)
+               pci_pool_destroy(mvi->dma_pool);
 
        if (mvi->tx)
                dma_free_coherent(mvi->dev,
@@ -141,11 +153,13 @@ static void mvs_free(struct mvs_info *mvi)
                dma_free_coherent(mvi->dev,
                                  sizeof(*mvi->slot) * slot_nr,
                                  mvi->slot, mvi->slot_dma);
-#ifndef DISABLE_HOTPLUG_DMA_FIX
+
        if (mvi->bulk_buffer)
                dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE,
                                  mvi->bulk_buffer, mvi->bulk_buffer_dma);
-#endif
+       if (mvi->bulk_buffer1)
+               dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE,
+                                 mvi->bulk_buffer1, mvi->bulk_buffer_dma1);
 
        MVS_CHIP_DISP->chip_iounmap(mvi);
        if (mvi->shost)
@@ -213,6 +227,7 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)
 static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
 {
        int i = 0, slot_nr;
+       char pool_name[32];
 
        if (mvi->flags & MVF_FLAG_SOC)
                slot_nr = MVS_SOC_SLOTS;
@@ -265,25 +280,26 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
                goto err_out;
        memset(mvi->slot, 0, sizeof(*mvi->slot) * slot_nr);
 
-#ifndef DISABLE_HOTPLUG_DMA_FIX
        mvi->bulk_buffer = dma_alloc_coherent(mvi->dev,
                                       TRASH_BUCKET_SIZE,
                                       &mvi->bulk_buffer_dma, GFP_KERNEL);
        if (!mvi->bulk_buffer)
                goto err_out;
-#endif
-       for (i = 0; i < slot_nr; i++) {
-               struct mvs_slot_info *slot = &mvi->slot_info[i];
 
-               slot->buf = dma_alloc_coherent(mvi->dev, MVS_SLOT_BUF_SZ,
-                                              &slot->buf_dma, GFP_KERNEL);
-               if (!slot->buf) {
-                       printk(KERN_DEBUG"failed to allocate slot->buf.\n");
+       mvi->bulk_buffer1 = dma_alloc_coherent(mvi->dev,
+                                      TRASH_BUCKET_SIZE,
+                                      &mvi->bulk_buffer_dma1, GFP_KERNEL);
+       if (!mvi->bulk_buffer1)
+               goto err_out;
+
+       sprintf(pool_name, "%s%d", "mvs_dma_pool", mvi->id);
+       mvi->dma_pool = pci_pool_create(pool_name, mvi->pdev, MVS_SLOT_BUF_SZ, 16, 0);
+       if (!mvi->dma_pool) {
+                       printk(KERN_DEBUG "failed to create dma pool %s.\n", pool_name);
                        goto err_out;
-               }
-               memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
-               ++mvi->tags_num;
        }
+       mvi->tags_num = slot_nr;
+
        /* Initialize tags */
        mvs_tag_init(mvi);
        return 0;
@@ -484,7 +500,7 @@ static void  __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost,
 
        sha->num_phys = nr_core * chip_info->n_phy;
 
-       sha->lldd_max_execute_num = 1;
+       sha->lldd_max_execute_num = lldd_max_execute_num;
 
        if (mvi->flags & MVF_FLAG_SOC)
                can_queue = MVS_SOC_CAN_QUEUE;
@@ -565,6 +581,9 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
                        goto err_out_regions;
                }
 
+               memset(&mvi->hba_info_param, 0xFF,
+                       sizeof(struct hba_info_page));
+
                mvs_init_sas_add(mvi);
 
                mvi->instance = nhost;
@@ -670,6 +689,24 @@ static struct pci_device_id __devinitdata mvs_pci_table[] = {
        { PCI_VDEVICE(TTI, 0x2740), chip_9480 },
        { PCI_VDEVICE(TTI, 0x2744), chip_9480 },
        { PCI_VDEVICE(TTI, 0x2760), chip_9480 },
+       {
+               .vendor         = 0x1b4b,
+               .device         = 0x9445,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = 0x9480,
+               .class          = 0,
+               .class_mask     = 0,
+               .driver_data    = chip_9445,
+       },
+       {
+               .vendor         = 0x1b4b,
+               .device         = 0x9485,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = 0x9480,
+               .class          = 0,
+               .class_mask     = 0,
+               .driver_data    = chip_9485,
+       },
 
        { }     /* terminate list */
 };
@@ -681,6 +718,70 @@ static struct pci_driver mvs_pci_driver = {
        .remove         = __devexit_p(mvs_pci_remove),
 };
 
+static ssize_t
+mvs_show_driver_version(struct device *cdev,
+               struct device_attribute *attr,  char *buffer)
+{
+       return snprintf(buffer, PAGE_SIZE, "%s\n", DRV_VERSION);
+}
+
+static DEVICE_ATTR(driver_version,
+                        S_IRUGO,
+                        mvs_show_driver_version,
+                        NULL);
+
+static ssize_t
+mvs_store_interrupt_coalescing(struct device *cdev,
+                       struct device_attribute *attr,
+                       const char *buffer, size_t size)
+{
+       int val = 0;
+       struct mvs_info *mvi = NULL;
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+       u8 i, core_nr;
+       if (buffer == NULL)
+               return size;
+
+       if (sscanf(buffer, "%d", &val) != 1)
+               return -EINVAL;
+
+       if (val >= 0x10000) {
+               mv_dprintk("interrupt coalescing timer %d us is"
+                       "too long\n", val);
+               return strlen(buffer);
+       }
+
+       interrupt_coalescing = val;
+
+       core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+       mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
+
+       if (unlikely(!mvi))
+               return -EINVAL;
+
+       for (i = 0; i < core_nr; i++) {
+               mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
+               if (MVS_CHIP_DISP->tune_interrupt)
+                       MVS_CHIP_DISP->tune_interrupt(mvi,
+                               interrupt_coalescing);
+       }
+       mv_dprintk("set interrupt coalescing time to %d us\n",
+               interrupt_coalescing);
+       return strlen(buffer);
+}
+
+static ssize_t mvs_show_interrupt_coalescing(struct device *cdev,
+                       struct device_attribute *attr, char *buffer)
+{
+       return snprintf(buffer, PAGE_SIZE, "%d\n", interrupt_coalescing);
+}
+
+static DEVICE_ATTR(interrupt_coalescing,
+                        S_IRUGO|S_IWUSR,
+                        mvs_show_interrupt_coalescing,
+                        mvs_store_interrupt_coalescing);
+
 /* task handler */
 struct task_struct *mvs_th;
 static int __init mvs_init(void)
@@ -690,6 +791,14 @@ static int __init mvs_init(void)
        if (!mvs_stt)
                return -ENOMEM;
 
+       mvs_task_list_cache = kmem_cache_create("mvs_task_list", sizeof(struct mvs_task_list),
+                                                        0, SLAB_HWCACHE_ALIGN, NULL);
+       if (!mvs_task_list_cache) {
+               rc = -ENOMEM;
+               mv_printk("%s: mvs_task_list_cache alloc failed! \n", __func__);
+               goto err_out;
+       }
+
        rc = pci_register_driver(&mvs_pci_driver);
 
        if (rc)
@@ -706,8 +815,15 @@ static void __exit mvs_exit(void)
 {
        pci_unregister_driver(&mvs_pci_driver);
        sas_release_transport(mvs_stt);
+       kmem_cache_destroy(mvs_task_list_cache);
 }
 
+struct device_attribute *mvst_host_attrs[] = {
+       &dev_attr_driver_version,
+       &dev_attr_interrupt_coalescing,
+       NULL,
+};
+
 module_init(mvs_init);
 module_exit(mvs_exit);