[PATCH 4/5] scsi: megaraid_sas - preallocate memory for ioctl processing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Preallocate memory for ioctl processing. This is to avoid situations 
where ioctl fails for lack of memory (when system under heavy stress).
The memory pool will have 8*4K, 4*8K and 1*64K memory chunks

Signed-off-by: Sumant Patro <sumant.patro@xxxxxxx>

 drivers/scsi/megaraid/megaraid_sas.c |  257 ++++++++++++++++++++++++-
 drivers/scsi/megaraid/megaraid_sas.h |   32 ++-
 2 files changed, 276 insertions(+), 13 deletions(-)

diff -uprN 2.6.new-p3/drivers/scsi/megaraid/megaraid_sas.c 2.6.new-p4/drivers/scsi/megaraid/megaraid_sas.c
--- 2.6.new-p3/drivers/scsi/megaraid/megaraid_sas.c	2007-02-06 08:50:40.000000000 -0800
+++ 2.6.new-p4/drivers/scsi/megaraid/megaraid_sas.c	2007-02-06 13:12:42.000000000 -0800
@@ -74,6 +74,14 @@ static DEFINE_MUTEX(megasas_async_queue_
 
 static u32 megasas_dbg_lvl;
 
+/* For IOCTL mem pool */
+int arr[MAX_IOCTL_MEM_POOL] = {MAX_4K_BUFF,MAX_8K_BUFF,MAX_64K_BUFF};
+
+int arr_size[MAX_IOCTL_MEM_POOL] =
+			{MEGASAS_INIT_IOCTL_MEM_SIZE/* 4k */,
+			2*MEGASAS_INIT_IOCTL_MEM_SIZE/* 8k */,
+			16*MEGASAS_INIT_IOCTL_MEM_SIZE/* 64k */};
+
 /**
  * megasas_get_cmd -	Get a command from the free pool
  * @instance:		Adapter soft state
@@ -1805,6 +1813,194 @@ megasas_get_ctrl_info(struct megasas_ins
 }
 
 /**
+ * megasas_get_ioctl_mem -	Get a buff from the free ioctl memory pool
+ * @instance:			Adapter soft state
+ * @i:				mem pool index
+ *
+ * Returns a free buff from the pool
+ */
+static inline struct megasas_ioctl_mm *
+megasas_get_ioctl_mem(struct megasas_instance* instance, u8 i)
+{
+	unsigned long flags;
+	struct megasas_ioctl_mm *ioctl_mm = NULL;
+
+	if(i >= MAX_IOCTL_MEM_POOL)
+		goto out;
+
+	spin_lock_irqsave(&instance->ioctl_memory_pool_lock, flags);
+
+	if (!list_empty(&instance->ioctl_memory_pool[i])) {
+		ioctl_mm = list_entry((&instance->ioctl_memory_pool[i])->next,
+				 struct megasas_ioctl_mm, list);
+		list_del_init(&ioctl_mm->list);
+	} else
+		printk(KERN_DEBUG "megasas: ioctl memory pool empty!\n");
+
+	spin_unlock_irqrestore(&instance->ioctl_memory_pool_lock, flags);
+out:
+	return ioctl_mm;
+}
+
+/**
+ * megasas_return_ioctl_mm -	Return memory to ioctl memory pool
+ * @instance:			Adapter soft state
+ * @megasas_ioctl_mm:		ioctl mem block
+ * @i:				mem_pool_index
+ */
+static inline void
+megasas_return_ioctl_mem(struct megasas_instance *instance,
+			struct megasas_ioctl_mm *ioctl_mm, u8 i)
+{
+	unsigned long flags;
+	if(!ioctl_mm){
+		printk(KERN_DEBUG "megasas: Trying to return "
+					"NULL to mem_pool\n");
+		return;
+	}
+	spin_lock_irqsave(&instance->ioctl_memory_pool_lock, flags);
+	list_add_tail(&ioctl_mm->list, &instance->ioctl_memory_pool[i]);
+	spin_unlock_irqrestore(&instance->ioctl_memory_pool_lock, flags);
+}
+
+/**
+ * megasas_free_ioctl_mem_pools - Free all the memory in the ioctl memory pool
+ * @instance:			Adapter soft state
+ */
+static void
+megasas_free_ioctl_mem_pools(struct megasas_instance *instance)
+{
+	struct megasas_ioctl_mm	*ioctl_mm;
+	u32 i,j;
+	u32 mem_size;
+	if(instance->mem_pool_empty)
+		return;
+	for (i=0; i < MAX_IOCTL_MEM_POOL; i++) {
+		mem_size = arr_size[i];
+		for (j = 0; j < arr[i]; j++) {
+			ioctl_mm = megasas_get_ioctl_mem(instance, i);
+
+			if (ioctl_mm){
+				if(ioctl_mm->vaddr)
+					pci_free_consistent(instance->pdev,
+							mem_size,
+							ioctl_mm->vaddr,
+						 	ioctl_mm->buf_handle);
+				kfree(ioctl_mm);
+			}
+		}
+	}
+}
+
+/**
+ * megasas_setup_mem_pools - Setup memory in the ioctl memory pool
+ * @instance:		Adapter soft state
+ *
+ * The memory pool will have 8x4K, 4*8K and 1x64K memory
+ * ioctl_memory_pool[0] ----> 4k memory list
+ * ioctl_memory_pool[1] ----> 8K memory list
+ * ioctl_memory_pool[2] ----> 64K memory list
+ */
+
+static int
+megasas_setup_mem_pools(struct megasas_instance *instance)
+{
+	struct megasas_ioctl_mm	*ioctl_mm;
+	dma_addr_t buf_handle;
+	void *vaddr;
+	u32 i, j;
+	u32 mem_size;
+	for (i=0; i < MAX_IOCTL_MEM_POOL; i++) {
+		mem_size = arr_size[i];
+
+		for (j = 0; j < arr[i]; j++) {
+
+			ioctl_mm = kmalloc(sizeof(struct megasas_ioctl_mm), GFP_KERNEL);	
+			if(!ioctl_mm){
+				printk(KERN_DEBUG "megasas:Failed to alloc "
+						"init memory for ioctl \n");
+				goto failed_to_alloc_mem_ioctl;
+			}
+			vaddr = pci_alloc_consistent(instance->pdev,mem_size,
+							    &buf_handle);
+			if (!vaddr) {
+				printk(KERN_DEBUG "megasas:Failed to alloc "
+						"memory for ioctl \n");
+				goto failed_to_alloc_mem_ioctl;
+			} else {
+				ioctl_mm->vaddr	= vaddr;
+				ioctl_mm->buf_handle = (u32)buf_handle;
+
+				list_add_tail(&ioctl_mm->list,
+					&instance->ioctl_memory_pool[i]);
+			}
+		}
+	}
+	return 0;
+failed_to_alloc_mem_ioctl:
+	megasas_free_ioctl_mem_pools(instance);
+	return 1;
+}
+
+/**
+ * megasas_get_buff_for_sge - Free all the memory in the ioctl memory pool
+ * @instance:		Adapter soft state
+ * @cmd:		megasas_cmd
+ */
+
+int
+megasas_get_buff_for_sge(struct megasas_iocpacket *ioc,
+			struct megasas_instance *instance,
+			struct megasas_cmd *cmd)
+{
+	int i,n;
+	u8 mem_type;
+	struct megasas_ioctl_mm* ioctl_mm;
+	if(instance->mem_pool_empty)
+		goto empty;
+	for (i = 0; i < ioc->sge_count; i++) {
+		/*
+		 * Check if we have buffer to use from our mem_pool
+		 * If we donot have enough to satisfy for all sge's then
+		 * free that has already been attached to the ioc
+		 */
+		mem_type=0xff;
+		if (ioc->sgl[i].iov_len <= MEGASAS_INIT_IOCTL_MEM_SIZE)
+			mem_type=0;
+		else if ((ioc->sgl[i].iov_len > MEGASAS_INIT_IOCTL_MEM_SIZE) &&
+			(ioc->sgl[i].iov_len <= 2*MEGASAS_INIT_IOCTL_MEM_SIZE))
+			mem_type=1;
+		else if ((ioc->sgl[i].iov_len > 2*MEGASAS_INIT_IOCTL_MEM_SIZE) &&
+			(ioc->sgl[i].iov_len <= 16*MEGASAS_INIT_IOCTL_MEM_SIZE))
+			mem_type=2;
+
+		ioctl_mm = megasas_get_ioctl_mem(instance, mem_type);
+			
+		if (ioctl_mm) {
+			cmd->ioctl_mem[i]=ioctl_mm;
+			cmd->ioctl_mem_pool_index[i] = mem_type;
+		} else
+			/* Not enough buffer in mem pool
+			 * Free all allocated buffer for this ioc
+			 */
+			goto out;
+	}
+	return 0;
+out:
+	for (n = 0; n < i; n++) {
+		if ((struct megasas_ioctl_mm *)cmd->ioctl_mem[i]) {
+			megasas_return_ioctl_mem(instance,
+				(struct megasas_ioctl_mm *)cmd->ioctl_mem[i],
+				cmd->ioctl_mem_pool_index[i]);
+			cmd->ioctl_mem[i]=NULL;
+			cmd->ioctl_mem_pool_index[i] = 0xff;
+		}
+	}
+empty:
+	return 1;
+}
+
+/**
  * megasas_complete_cmd_dpc	 -	Returns FW's controller structure
  * @instance_addr:			Address of adapter soft state
  *
@@ -2310,7 +2506,7 @@ static int megasas_io_attach(struct mega
 static int __devinit
 megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-	int rval;
+	int rval,i;
 	struct Scsi_Host *host;
 	struct megasas_instance *instance;
 
@@ -2396,10 +2592,23 @@ megasas_probe_one(struct pci_dev *pdev, 
 	init_waitqueue_head(&instance->abort_cmd_wait_q);
 
 	spin_lock_init(&instance->cmd_pool_lock);
+	spin_lock_init(&instance->ioctl_memory_pool_lock);
 
 	sema_init(&instance->aen_mutex, 1);
 	sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
 
+	/* 
+	 * for-ioctl: initialize ioctl memory list
+	 */
+	for (i=0; i<MAX_IOCTL_MEM_POOL; i++) {
+		INIT_LIST_HEAD(&instance->ioctl_memory_pool[i]);
+	}
+
+	if(megasas_setup_mem_pools(instance))
+		instance->mem_pool_empty=1;
+	
+	/* end for-ioctl */
+
 	/*
 	 * Initialize PCI related and misc parameters
 	 */
@@ -2472,6 +2681,8 @@ megasas_probe_one(struct pci_dev *pdev, 
       fail_irq:
       fail_init_mfi:
       fail_alloc_dma_buf:
+	/* Free ioctl mem pool */
+	megasas_free_ioctl_mem_pools(instance);
 	if (instance->evt_detail)
 		pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
 				    instance->evt_detail,
@@ -2600,6 +2811,9 @@ static void megasas_detach_one(struct pc
 	free_irq(instance->pdev->irq, instance);
 
 	megasas_release_mfi(instance);
+	/* Free IOCTL mem pool */
+	megasas_free_ioctl_mem_pools(instance);
+
 
 	pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
 			    instance->evt_detail, instance->evt_detail_h);
@@ -2699,6 +2913,7 @@ megasas_mgmt_fw_ioctl(struct megasas_ins
 	void *sense = NULL;
 	dma_addr_t sense_handle;
 	u32 *sense_ptr;
+	u8 from_pool = 0;
 
 	memset(kbuff_arr, 0, sizeof(kbuff_arr));
 
@@ -2734,18 +2949,30 @@ megasas_mgmt_fw_ioctl(struct megasas_ins
 	kern_sge32 = (struct megasas_sge32 *)
 	    ((unsigned long)cmd->frame + ioc->sgl_off);
 
+ 	/*
+	 * Check if we have buffer to use from our ioctl mem_pool
+	 * If we donot have then try to allocate new buffer
+	 */
+	if(!megasas_get_buff_for_sge(ioc,instance,cmd))
+		from_pool = 1;
+
 	/*
 	 * For each user buffer, create a mirror buffer and copy in
 	 */
 	for (i = 0; i < ioc->sge_count; i++) {
-		kbuff_arr[i] = pci_alloc_consistent(instance->pdev,
+		if (from_pool) {
+			kbuff_arr[i] = cmd->ioctl_mem[i]->vaddr;
+			buf_handle = cmd->ioctl_mem[i]->buf_handle;
+		} else {
+			kbuff_arr[i] = pci_alloc_consistent(instance->pdev,
 						    ioc->sgl[i].iov_len,
 						    &buf_handle);
-		if (!kbuff_arr[i]) {
-			printk(KERN_DEBUG "megasas: Failed to alloc "
-			       "kernel SGL buffer for IOCTL \n");
-			error = -ENOMEM;
-			goto out;
+			if (!kbuff_arr[i]) {
+				printk(KERN_DEBUG "megasas: Failed to alloc "
+					"kernel SGL buffer for IOCTL \n");
+				error = -ENOMEM;
+				goto out;
+			}
 		}
 
 		/*
@@ -2832,9 +3059,19 @@ megasas_mgmt_fw_ioctl(struct megasas_ins
 	}
 
 	for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) {
-		pci_free_consistent(instance->pdev,
-				    kern_sge32[i].length,
-				    kbuff_arr[i], kern_sge32[i].phys_addr);
+		if (from_pool) {
+			/* Return to the mem pool */
+			if ((struct megasas_ioctl_mm *)cmd->ioctl_mem[i]) {
+				megasas_return_ioctl_mem(instance,
+					(struct megasas_ioctl_mm *)cmd->ioctl_mem[i],
+					cmd->ioctl_mem_pool_index[i]);
+				cmd->ioctl_mem_pool_index[i]=0xff;
+				cmd->ioctl_mem[i]=NULL;
+			}
+		} else 
+			pci_free_consistent(instance->pdev,
+			    kern_sge32[i].length,
+			    kbuff_arr[i], kern_sge32[i].phys_addr);
 	}
 
 	megasas_return_cmd(instance, cmd);
diff -uprN 2.6.new-p3/drivers/scsi/megaraid/megaraid_sas.h 2.6.new-p4/drivers/scsi/megaraid/megaraid_sas.h
--- 2.6.new-p3/drivers/scsi/megaraid/megaraid_sas.h	2007-02-06 08:51:23.000000000 -0800
+++ 2.6.new-p4/drivers/scsi/megaraid/megaraid_sas.h	2007-02-06 10:14:17.000000000 -0800
@@ -539,6 +539,17 @@ struct megasas_ctrl_info {
 
 #define MEGASAS_DBG_LVL				1
 
+/* 
+ * For ioctl memory manager
+ */
+
+#define MAX_IOCTL_MEM_POOL			3
+#define MEGASAS_INIT_IOCTL_MEM_SIZE		4096
+#define MAX_IOCTL_MEM_BLOCK			16
+#define MAX_4K_BUFF				8
+#define MAX_8K_BUFF				4
+#define MAX_64K_BUFF				1
+
 /*
  * When SCSI mid-layer calls driver's reset routine, driver waits for
  * MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note
@@ -1059,6 +1070,12 @@ struct megasas_evt_detail {
 	u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *);
  };
 
+struct megasas_ioctl_mm {
+	void *vaddr;
+	dma_addr_t buf_handle;
+	struct list_head list;
+};
+
 struct megasas_instance {
 
 	u32 *producer;
@@ -1085,6 +1102,12 @@ struct megasas_instance {
 	struct dma_pool *frame_dma_pool;
 	struct dma_pool *sense_dma_pool;
 
+	/* ioctl memory */
+	struct list_head ioctl_memory_pool[MAX_IOCTL_MEM_POOL];
+	spinlock_t ioctl_memory_pool_lock;
+	u8 mem_pool_empty;
+	/* end :ioctl memory */
+
 	struct megasas_evt_detail *evt_detail;
 	dma_addr_t evt_detail_h;
 	struct megasas_cmd *aen_cmd;
@@ -1116,6 +1139,9 @@ struct megasas_instance {
 	((scp->device->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + 	\
 	scp->device->id
 
+#define MAX_MGMT_ADAPTERS		1024
+#define MAX_IOCTL_SGE			16
+
 struct megasas_cmd {
 
 	union megasas_frame *frame;
@@ -1132,10 +1158,10 @@ struct megasas_cmd {
 	struct scsi_cmnd *scmd;
 	struct megasas_instance *instance;
 	u32 frame_count;
-};
 
-#define MAX_MGMT_ADAPTERS		1024
-#define MAX_IOCTL_SGE			16
+	u8 ioctl_mem_pool_index[MAX_IOCTL_SGE]; /*0xff for not in use*/
+	struct megasas_ioctl_mm *ioctl_mem[MAX_IOCTL_SGE];
+};
 
 struct megasas_iocpacket {
 

diff -uprN 2.6.new-p3/drivers/scsi/megaraid/megaraid_sas.c 2.6.new-p4/drivers/scsi/megaraid/megaraid_sas.c
--- 2.6.new-p3/drivers/scsi/megaraid/megaraid_sas.c	2007-02-06 08:50:40.000000000 -0800
+++ 2.6.new-p4/drivers/scsi/megaraid/megaraid_sas.c	2007-02-06 13:12:42.000000000 -0800
@@ -74,6 +74,14 @@ static DEFINE_MUTEX(megasas_async_queue_
 
 static u32 megasas_dbg_lvl;
 
+/* For IOCTL mem pool */
+int arr[MAX_IOCTL_MEM_POOL] = {MAX_4K_BUFF,MAX_8K_BUFF,MAX_64K_BUFF};
+
+int arr_size[MAX_IOCTL_MEM_POOL] =
+			{MEGASAS_INIT_IOCTL_MEM_SIZE/* 4k */,
+			2*MEGASAS_INIT_IOCTL_MEM_SIZE/* 8k */,
+			16*MEGASAS_INIT_IOCTL_MEM_SIZE/* 64k */};
+
 /**
  * megasas_get_cmd -	Get a command from the free pool
  * @instance:		Adapter soft state
@@ -1805,6 +1813,194 @@ megasas_get_ctrl_info(struct megasas_ins
 }
 
 /**
+ * megasas_get_ioctl_mem -	Get a buff from the free ioctl memory pool
+ * @instance:			Adapter soft state
+ * @i:				mem pool index
+ *
+ * Returns a free buff from the pool
+ */
+static inline struct megasas_ioctl_mm *
+megasas_get_ioctl_mem(struct megasas_instance* instance, u8 i)
+{
+	unsigned long flags;
+	struct megasas_ioctl_mm *ioctl_mm = NULL;
+
+	if(i >= MAX_IOCTL_MEM_POOL)
+		goto out;
+
+	spin_lock_irqsave(&instance->ioctl_memory_pool_lock, flags);
+
+	if (!list_empty(&instance->ioctl_memory_pool[i])) {
+		ioctl_mm = list_entry((&instance->ioctl_memory_pool[i])->next,
+				 struct megasas_ioctl_mm, list);
+		list_del_init(&ioctl_mm->list);
+	} else
+		printk(KERN_DEBUG "megasas: ioctl memory pool empty!\n");
+
+	spin_unlock_irqrestore(&instance->ioctl_memory_pool_lock, flags);
+out:
+	return ioctl_mm;
+}
+
+/**
+ * megasas_return_ioctl_mm -	Return memory to ioctl memory pool
+ * @instance:			Adapter soft state
+ * @megasas_ioctl_mm:		ioctl mem block
+ * @i:				mem_pool_index
+ */
+static inline void
+megasas_return_ioctl_mem(struct megasas_instance *instance,
+			struct megasas_ioctl_mm *ioctl_mm, u8 i)
+{
+	unsigned long flags;
+	if(!ioctl_mm){
+		printk(KERN_DEBUG "megasas: Trying to return "
+					"NULL to mem_pool\n");
+		return;
+	}
+	spin_lock_irqsave(&instance->ioctl_memory_pool_lock, flags);
+	list_add_tail(&ioctl_mm->list, &instance->ioctl_memory_pool[i]);
+	spin_unlock_irqrestore(&instance->ioctl_memory_pool_lock, flags);
+}
+
+/**
+ * megasas_free_ioctl_mem_pools - Free all the memory in the ioctl memory pool
+ * @instance:			Adapter soft state
+ */
+static void
+megasas_free_ioctl_mem_pools(struct megasas_instance *instance)
+{
+	struct megasas_ioctl_mm	*ioctl_mm;
+	u32 i,j;
+	u32 mem_size;
+	if(instance->mem_pool_empty)
+		return;
+	for (i=0; i < MAX_IOCTL_MEM_POOL; i++) {
+		mem_size = arr_size[i];
+		for (j = 0; j < arr[i]; j++) {
+			ioctl_mm = megasas_get_ioctl_mem(instance, i);
+
+			if (ioctl_mm){
+				if(ioctl_mm->vaddr)
+					pci_free_consistent(instance->pdev,
+							mem_size,
+							ioctl_mm->vaddr,
+						 	ioctl_mm->buf_handle);
+				kfree(ioctl_mm);
+			}
+		}
+	}
+}
+
+/**
+ * megasas_setup_mem_pools - Setup memory in the ioctl memory pool
+ * @instance:		Adapter soft state
+ *
+ * The memory pool will have 8x4K, 4*8K and 1x64K memory
+ * ioctl_memory_pool[0] ----> 4k memory list
+ * ioctl_memory_pool[1] ----> 8K memory list
+ * ioctl_memory_pool[2] ----> 64K memory list
+ */
+
+static int
+megasas_setup_mem_pools(struct megasas_instance *instance)
+{
+	struct megasas_ioctl_mm	*ioctl_mm;
+	dma_addr_t buf_handle;
+	void *vaddr;
+	u32 i, j;
+	u32 mem_size;
+	for (i=0; i < MAX_IOCTL_MEM_POOL; i++) {
+		mem_size = arr_size[i];
+
+		for (j = 0; j < arr[i]; j++) {
+
+			ioctl_mm = kmalloc(sizeof(struct megasas_ioctl_mm), GFP_KERNEL);	
+			if(!ioctl_mm){
+				printk(KERN_DEBUG "megasas:Failed to alloc "
+						"init memory for ioctl \n");
+				goto failed_to_alloc_mem_ioctl;
+			}
+			vaddr = pci_alloc_consistent(instance->pdev,mem_size,
+							    &buf_handle);
+			if (!vaddr) {
+				printk(KERN_DEBUG "megasas:Failed to alloc "
+						"memory for ioctl \n");
+				goto failed_to_alloc_mem_ioctl;
+			} else {
+				ioctl_mm->vaddr	= vaddr;
+				ioctl_mm->buf_handle = (u32)buf_handle;
+
+				list_add_tail(&ioctl_mm->list,
+					&instance->ioctl_memory_pool[i]);
+			}
+		}
+	}
+	return 0;
+failed_to_alloc_mem_ioctl:
+	megasas_free_ioctl_mem_pools(instance);
+	return 1;
+}
+
+/**
+ * megasas_get_buff_for_sge - Free all the memory in the ioctl memory pool
+ * @instance:		Adapter soft state
+ * @cmd:		megasas_cmd
+ */
+
+int
+megasas_get_buff_for_sge(struct megasas_iocpacket *ioc,
+			struct megasas_instance *instance,
+			struct megasas_cmd *cmd)
+{
+	int i,n;
+	u8 mem_type;
+	struct megasas_ioctl_mm* ioctl_mm;
+	if(instance->mem_pool_empty)
+		goto empty;
+	for (i = 0; i < ioc->sge_count; i++) {
+		/*
+		 * Check if we have buffer to use from our mem_pool
+		 * If we donot have enough to satisfy for all sge's then
+		 * free that has already been attached to the ioc
+		 */
+		mem_type=0xff;
+		if (ioc->sgl[i].iov_len <= MEGASAS_INIT_IOCTL_MEM_SIZE)
+			mem_type=0;
+		else if ((ioc->sgl[i].iov_len > MEGASAS_INIT_IOCTL_MEM_SIZE) &&
+			(ioc->sgl[i].iov_len <= 2*MEGASAS_INIT_IOCTL_MEM_SIZE))
+			mem_type=1;
+		else if ((ioc->sgl[i].iov_len > 2*MEGASAS_INIT_IOCTL_MEM_SIZE) &&
+			(ioc->sgl[i].iov_len <= 16*MEGASAS_INIT_IOCTL_MEM_SIZE))
+			mem_type=2;
+
+		ioctl_mm = megasas_get_ioctl_mem(instance, mem_type);
+			
+		if (ioctl_mm) {
+			cmd->ioctl_mem[i]=ioctl_mm;
+			cmd->ioctl_mem_pool_index[i] = mem_type;
+		} else
+			/* Not enough buffer in mem pool
+			 * Free all allocated buffer for this ioc
+			 */
+			goto out;
+	}
+	return 0;
+out:
+	for (n = 0; n < i; n++) {
+		if ((struct megasas_ioctl_mm *)cmd->ioctl_mem[i]) {
+			megasas_return_ioctl_mem(instance,
+				(struct megasas_ioctl_mm *)cmd->ioctl_mem[i],
+				cmd->ioctl_mem_pool_index[i]);
+			cmd->ioctl_mem[i]=NULL;
+			cmd->ioctl_mem_pool_index[i] = 0xff;
+		}
+	}
+empty:
+	return 1;
+}
+
+/**
  * megasas_complete_cmd_dpc	 -	Returns FW's controller structure
  * @instance_addr:			Address of adapter soft state
  *
@@ -2310,7 +2506,7 @@ static int megasas_io_attach(struct mega
 static int __devinit
 megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-	int rval;
+	int rval,i;
 	struct Scsi_Host *host;
 	struct megasas_instance *instance;
 
@@ -2396,10 +2592,23 @@ megasas_probe_one(struct pci_dev *pdev, 
 	init_waitqueue_head(&instance->abort_cmd_wait_q);
 
 	spin_lock_init(&instance->cmd_pool_lock);
+	spin_lock_init(&instance->ioctl_memory_pool_lock);
 
 	sema_init(&instance->aen_mutex, 1);
 	sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
 
+	/* 
+	 * for-ioctl: initialize ioctl memory list
+	 */
+	for (i=0; i<MAX_IOCTL_MEM_POOL; i++) {
+		INIT_LIST_HEAD(&instance->ioctl_memory_pool[i]);
+	}
+
+	if(megasas_setup_mem_pools(instance))
+		instance->mem_pool_empty=1;
+	
+	/* end for-ioctl */
+
 	/*
 	 * Initialize PCI related and misc parameters
 	 */
@@ -2472,6 +2681,8 @@ megasas_probe_one(struct pci_dev *pdev, 
       fail_irq:
       fail_init_mfi:
       fail_alloc_dma_buf:
+	/* Free ioctl mem pool */
+	megasas_free_ioctl_mem_pools(instance);
 	if (instance->evt_detail)
 		pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
 				    instance->evt_detail,
@@ -2600,6 +2811,9 @@ static void megasas_detach_one(struct pc
 	free_irq(instance->pdev->irq, instance);
 
 	megasas_release_mfi(instance);
+	/* Free IOCTL mem pool */
+	megasas_free_ioctl_mem_pools(instance);
+
 
 	pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
 			    instance->evt_detail, instance->evt_detail_h);
@@ -2699,6 +2913,7 @@ megasas_mgmt_fw_ioctl(struct megasas_ins
 	void *sense = NULL;
 	dma_addr_t sense_handle;
 	u32 *sense_ptr;
+	u8 from_pool = 0;
 
 	memset(kbuff_arr, 0, sizeof(kbuff_arr));
 
@@ -2734,18 +2949,30 @@ megasas_mgmt_fw_ioctl(struct megasas_ins
 	kern_sge32 = (struct megasas_sge32 *)
 	    ((unsigned long)cmd->frame + ioc->sgl_off);
 
+ 	/*
+	 * Check if we have buffer to use from our ioctl mem_pool
+	 * If we donot have then try to allocate new buffer
+	 */
+	if(!megasas_get_buff_for_sge(ioc,instance,cmd))
+		from_pool = 1;
+
 	/*
 	 * For each user buffer, create a mirror buffer and copy in
 	 */
 	for (i = 0; i < ioc->sge_count; i++) {
-		kbuff_arr[i] = pci_alloc_consistent(instance->pdev,
+		if (from_pool) {
+			kbuff_arr[i] = cmd->ioctl_mem[i]->vaddr;
+			buf_handle = cmd->ioctl_mem[i]->buf_handle;
+		} else {
+			kbuff_arr[i] = pci_alloc_consistent(instance->pdev,
 						    ioc->sgl[i].iov_len,
 						    &buf_handle);
-		if (!kbuff_arr[i]) {
-			printk(KERN_DEBUG "megasas: Failed to alloc "
-			       "kernel SGL buffer for IOCTL \n");
-			error = -ENOMEM;
-			goto out;
+			if (!kbuff_arr[i]) {
+				printk(KERN_DEBUG "megasas: Failed to alloc "
+					"kernel SGL buffer for IOCTL \n");
+				error = -ENOMEM;
+				goto out;
+			}
 		}
 
 		/*
@@ -2832,9 +3059,19 @@ megasas_mgmt_fw_ioctl(struct megasas_ins
 	}
 
 	for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) {
-		pci_free_consistent(instance->pdev,
-				    kern_sge32[i].length,
-				    kbuff_arr[i], kern_sge32[i].phys_addr);
+		if (from_pool) {
+			/* Return to the mem pool */
+			if ((struct megasas_ioctl_mm *)cmd->ioctl_mem[i]) {
+				megasas_return_ioctl_mem(instance,
+					(struct megasas_ioctl_mm *)cmd->ioctl_mem[i],
+					cmd->ioctl_mem_pool_index[i]);
+				cmd->ioctl_mem_pool_index[i]=0xff;
+				cmd->ioctl_mem[i]=NULL;
+			}
+		} else 
+			pci_free_consistent(instance->pdev,
+			    kern_sge32[i].length,
+			    kbuff_arr[i], kern_sge32[i].phys_addr);
 	}
 
 	megasas_return_cmd(instance, cmd);
diff -uprN 2.6.new-p3/drivers/scsi/megaraid/megaraid_sas.h 2.6.new-p4/drivers/scsi/megaraid/megaraid_sas.h
--- 2.6.new-p3/drivers/scsi/megaraid/megaraid_sas.h	2007-02-06 08:51:23.000000000 -0800
+++ 2.6.new-p4/drivers/scsi/megaraid/megaraid_sas.h	2007-02-06 10:14:17.000000000 -0800
@@ -539,6 +539,17 @@ struct megasas_ctrl_info {
 
 #define MEGASAS_DBG_LVL				1
 
+/* 
+ * For ioctl memory manager
+ */
+
+#define MAX_IOCTL_MEM_POOL			3
+#define MEGASAS_INIT_IOCTL_MEM_SIZE		4096
+#define MAX_IOCTL_MEM_BLOCK			16
+#define MAX_4K_BUFF				8
+#define MAX_8K_BUFF				4
+#define MAX_64K_BUFF				1
+
 /*
  * When SCSI mid-layer calls driver's reset routine, driver waits for
  * MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note
@@ -1059,6 +1070,12 @@ struct megasas_evt_detail {
 	u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *);
  };
 
+struct megasas_ioctl_mm {
+	void *vaddr;
+	dma_addr_t buf_handle;
+	struct list_head list;
+};
+
 struct megasas_instance {
 
 	u32 *producer;
@@ -1085,6 +1102,12 @@ struct megasas_instance {
 	struct dma_pool *frame_dma_pool;
 	struct dma_pool *sense_dma_pool;
 
+	/* ioctl memory */
+	struct list_head ioctl_memory_pool[MAX_IOCTL_MEM_POOL];
+	spinlock_t ioctl_memory_pool_lock;
+	u8 mem_pool_empty;
+	/* end :ioctl memory */
+
 	struct megasas_evt_detail *evt_detail;
 	dma_addr_t evt_detail_h;
 	struct megasas_cmd *aen_cmd;
@@ -1116,6 +1139,9 @@ struct megasas_instance {
 	((scp->device->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + 	\
 	scp->device->id
 
+#define MAX_MGMT_ADAPTERS		1024
+#define MAX_IOCTL_SGE			16
+
 struct megasas_cmd {
 
 	union megasas_frame *frame;
@@ -1132,10 +1158,10 @@ struct megasas_cmd {
 	struct scsi_cmnd *scmd;
 	struct megasas_instance *instance;
 	u32 frame_count;
-};
 
-#define MAX_MGMT_ADAPTERS		1024
-#define MAX_IOCTL_SGE			16
+	u8 ioctl_mem_pool_index[MAX_IOCTL_SGE]; /*0xff for not in use*/
+	struct megasas_ioctl_mm *ioctl_mem[MAX_IOCTL_SGE];
+};
 
 struct megasas_iocpacket {
 

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux