<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">

Patch from Stephen Cameron &lt;steve.cameron@hp.com&gt;

Add new big passthrough ioctl to allow large buffers.  Used by e.g.  online
array controller firmware flash utility.



 drivers/block/cciss.c       |  148 +++++++++++++++++++++++++++++++++++++++++++-
 include/linux/cciss_ioctl.h |   13 +++
 2 files changed, 160 insertions(+), 1 deletion(-)

diff -puN drivers/block/cciss.c~cciss-passthrough-ioctl drivers/block/cciss.c
--- 25/drivers/block/cciss.c~cciss-passthrough-ioctl	2003-02-27 17:05:57.000000000 -0800
+++ 25-akpm/drivers/block/cciss.c	2003-02-27 17:05:57.000000000 -0800
@@ -716,7 +716,153 @@ static int cciss_ioctl(struct inode *ino
 		cmd_free(h, c, 0);
                 return(0);
 	} 
-
+	case CCISS_BIG_PASSTHRU: {
+		BIG_IOCTL_Command_struct *ioc;
+		ctlr_info_t *h = hba[ctlr];
+		CommandList_struct *c;
+		unsigned char **buff = NULL;
+		int	*buff_size = NULL;
+		u64bit	temp64;
+		unsigned long flags;
+		BYTE sg_used = 0;
+		int status = 0;
+		int i;
+		DECLARE_COMPLETION(wait);
+		__u32   left;
+		__u32	sz;
+		BYTE    *data_ptr;
+
+		if (!arg)
+			return -EINVAL;
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		ioc = (BIG_IOCTL_Command_struct *) 
+			kmalloc(sizeof(*ioc), GFP_KERNEL);
+		if (!ioc) {
+			status = -ENOMEM;
+			goto cleanup1;
+		}
+		if (copy_from_user(ioc, (void *) arg, sizeof(*ioc)))
+			return -EFAULT;
+		if ((ioc-&gt;buf_size &lt; 1) &amp;&amp;
+			(ioc-&gt;Request.Type.Direction != XFER_NONE))
+				return -EINVAL;
+		/* Check kmalloc limits  using all SGs */
+		if (ioc-&gt;malloc_size &gt; MAX_KMALLOC_SIZE)
+			return -EINVAL;
+		if (ioc-&gt;buf_size &gt; ioc-&gt;malloc_size * MAXSGENTRIES)
+			return -EINVAL;
+		buff = (unsigned char **) kmalloc(MAXSGENTRIES * 
+				sizeof(char *), GFP_KERNEL);
+		if (!buff) {
+			status = -ENOMEM;
+			goto cleanup1;
+		}
+		memset(buff, 0, MAXSGENTRIES);
+		buff_size = (int *) kmalloc(MAXSGENTRIES * sizeof(int), 
+					GFP_KERNEL);
+		if (!buff_size) {
+			status = -ENOMEM;
+			goto cleanup1;
+		}
+		left = ioc-&gt;buf_size;
+		data_ptr = (BYTE *) ioc-&gt;buf;
+		while (left) {
+			sz = (left &gt; ioc-&gt;malloc_size) ? ioc-&gt;malloc_size : left;
+			buff_size[sg_used] = sz;
+			buff[sg_used] = kmalloc(sz, GFP_KERNEL);
+			if (buff[sg_used] == NULL) {
+				status = -ENOMEM;
+				goto cleanup1;
+			}
+			if (ioc-&gt;Request.Type.Direction == XFER_WRITE &amp;&amp;
+				copy_from_user(buff[sg_used], data_ptr, sz)) {
+					status = -ENOMEM;
+					goto cleanup1;			
+			}
+			left -= sz;
+			data_ptr += sz;
+			sg_used++;
+		}
+		if ((c = cmd_alloc(h , 0)) == NULL) {
+			status = -ENOMEM;
+			goto cleanup1;	
+		}
+		c-&gt;cmd_type = CMD_IOCTL_PEND;
+		c-&gt;Header.ReplyQueue = 0;
+		
+		if( ioc-&gt;buf_size &gt; 0) {
+			c-&gt;Header.SGList = sg_used;
+			c-&gt;Header.SGTotal= sg_used;
+		} else { 
+			c-&gt;Header.SGList = 0;
+			c-&gt;Header.SGTotal= 0;
+		}
+		c-&gt;Header.LUN = ioc-&gt;LUN_info;
+		c-&gt;Header.Tag.lower = c-&gt;busaddr;
+		
+		c-&gt;Request = ioc-&gt;Request;
+		if (ioc-&gt;buf_size &gt; 0 ) {
+			int i;
+			for(i=0; i&lt;sg_used; i++) {
+				temp64.val = pci_map_single( h-&gt;pdev, buff[i],
+					buff_size[i],
+					PCI_DMA_BIDIRECTIONAL);
+				c-&gt;SG[i].Addr.lower = temp64.val32.lower;
+				c-&gt;SG[i].Addr.upper = temp64.val32.upper;
+				c-&gt;SG[i].Len = buff_size[i];
+				c-&gt;SG[i].Ext = 0;  /* we are not chaining */
+			}
+		}
+		c-&gt;waiting = &amp;wait;
+		/* Put the request on the tail of the request queue */
+		spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+		addQ(&amp;h-&gt;reqQ, c);
+		h-&gt;Qdepth++;
+		start_io(h);
+		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+		wait_for_completion(&amp;wait);
+		/* unlock the buffers from DMA */
+		for(i=0; i&lt;sg_used; i++) {
+			temp64.val32.lower = c-&gt;SG[i].Addr.lower;
+			temp64.val32.upper = c-&gt;SG[i].Addr.upper;
+			pci_unmap_single( h-&gt;pdev, (dma_addr_t) temp64.val,
+				buff_size[i], PCI_DMA_BIDIRECTIONAL);
+		}
+		/* Copy the error information out */
+		ioc-&gt;error_info = *(c-&gt;err_info);
+		if (copy_to_user((void *) arg, ioc, sizeof(*ioc))) {
+			cmd_free(h, c, 0);
+			status = -EFAULT;
+			goto cleanup1;
+		}
+		if (ioc-&gt;Request.Type.Direction == XFER_READ) {
+			/* Copy the data out of the buffer we created */
+			BYTE *ptr = (BYTE  *) ioc-&gt;buf;
+	        	for(i=0; i&lt; sg_used; i++) {
+				if (copy_to_user(ptr, buff[i], buff_size[i])) {
+					cmd_free(h, c, 0);
+					status = -EFAULT;
+					goto cleanup1;
+				}
+				ptr += buff_size[i];
+			}
+		}
+		cmd_free(h, c, 0);
+		status = 0;
+cleanup1:
+		if (buff) {
+			for(i=0; i&lt;sg_used; i++)
+				if(buff[i] != NULL)
+					kfree(buff[i]);
+			kfree(buff);
+		}
+		if (buff_size)
+			kfree(buff_size);
+		if (ioc)
+			kfree(ioc);
+		return(status);
+	}
 	default:
 		return -EBADRQC;
 	}
diff -puN include/linux/cciss_ioctl.h~cciss-passthrough-ioctl include/linux/cciss_ioctl.h
--- 25/include/linux/cciss_ioctl.h~cciss-passthrough-ioctl	2003-02-27 17:05:57.000000000 -0800
+++ 25-akpm/include/linux/cciss_ioctl.h	2003-02-27 17:05:57.000000000 -0800
@@ -33,6 +33,18 @@ typedef __u32 BusTypes_type;
 typedef char FirmwareVer_type[4];
 typedef __u32 DriverVer_type;
 
+#define MAX_KMALLOC_SIZE 128000
+
+typedef struct _BIG_IOCTL_Command_struct {
+  LUNAddr_struct	   LUN_info;
+  RequestBlock_struct      Request;
+  ErrorInfo_struct  	   error_info; 
+  DWORD			   malloc_size; /* &lt; MAX_KMALLOC_SIZE in cciss.c */
+  DWORD			   buf_size;    /* size in bytes of the buf */
+  				        /* &lt; malloc_size * MAXSGENTRIES */
+  BYTE			   *buf;
+} BIG_IOCTL_Command_struct;
+
 
 #ifndef CCISS_CMD_H
 // This defines are duplicated in cciss_cmd.h in the driver directory 
@@ -196,5 +208,6 @@ typedef struct _LogvolInfo_struct{
 
 #define CCISS_REGNEWD	   _IO(CCISS_IOC_MAGIC, 14)
 #define CCISS_GETLUNINFO   _IOR(CCISS_IOC_MAGIC, 17, LogvolInfo_struct)
+#define CCISS_BIG_PASSTHRU _IOWR(CCISS_IOC_MAGIC, 18, BIG_IOCTL_Command_struct)
 
 #endif  

_
</pre></body></html>