[SCSI] mvsas: fix 94xx hotplug issue
[pandora-kernel.git] / drivers / scsi / mvsas / mv_init.c
index 90b6366..b111ae2 100644 (file)
@@ -34,6 +34,8 @@ MODULE_PARM_DESC(collector, "\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[] = {
@@ -48,6 +50,8 @@ static const struct mvs_chip_info mvs_chips[] = {
        [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
 
@@ -74,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 = {
@@ -148,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)
@@ -273,13 +280,18 @@ 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
+
+       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) {
@@ -569,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;
@@ -703,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)
@@ -739,6 +818,12 @@ static void __exit mvs_exit(void)
        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);