lkml.org 
[lkml]   [2003]   [Feb]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: [PATCH] 2.5.63 cciss fix unlikely startup problem
Another cciss patch for 2.5.63

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

-- steve

--- linux-2.5.63/drivers/block/cciss.c~bigioctl 2003-02-27 14:11:56.000000000 +0600
+++ linux-2.5.63-scameron/drivers/block/cciss.c 2003-02-27 14:11:56.000000000 +0600
@@ -728,7 +728,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->buf_size < 1) &&
+ (ioc->Request.Type.Direction != XFER_NONE))
+ return -EINVAL;
+ /* Check kmalloc limits using all SGs */
+ if (ioc->malloc_size > MAX_KMALLOC_SIZE)
+ return -EINVAL;
+ if (ioc->buf_size > ioc->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->buf_size;
+ data_ptr = (BYTE *) ioc->buf;
+ while (left) {
+ sz = (left > ioc->malloc_size) ? ioc->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->Request.Type.Direction == XFER_WRITE &&
+ 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->cmd_type = CMD_IOCTL_PEND;
+ c->Header.ReplyQueue = 0;
+
+ if( ioc->buf_size > 0) {
+ c->Header.SGList = sg_used;
+ c->Header.SGTotal= sg_used;
+ } else {
+ c->Header.SGList = 0;
+ c->Header.SGTotal= 0;
+ }
+ c->Header.LUN = ioc->LUN_info;
+ c->Header.Tag.lower = c->busaddr;
+
+ c->Request = ioc->Request;
+ if (ioc->buf_size > 0 ) {
+ int i;
+ for(i=0; i<sg_used; i++) {
+ temp64.val = pci_map_single( h->pdev, buff[i],
+ buff_size[i],
+ PCI_DMA_BIDIRECTIONAL);
+ c->SG[i].Addr.lower = temp64.val32.lower;
+ c->SG[i].Addr.upper = temp64.val32.upper;
+ c->SG[i].Len = buff_size[i];
+ c->SG[i].Ext = 0; /* we are not chaining */
+ }
+ }
+ c->waiting = &wait;
+ /* Put the request on the tail of the request queue */
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ addQ(&h->reqQ, c);
+ h->Qdepth++;
+ start_io(h);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ wait_for_completion(&wait);
+ /* unlock the buffers from DMA */
+ for(i=0; i<sg_used; i++) {
+ temp64.val32.lower = c->SG[i].Addr.lower;
+ temp64.val32.upper = c->SG[i].Addr.upper;
+ pci_unmap_single( h->pdev, (dma_addr_t) temp64.val,
+ buff_size[i], PCI_DMA_BIDIRECTIONAL);
+ }
+ /* Copy the error information out */
+ ioc->error_info = *(c->err_info);
+ if (copy_to_user((void *) arg, ioc, sizeof(*ioc))) {
+ cmd_free(h, c, 0);
+ status = -EFAULT;
+ goto cleanup1;
+ }
+ if (ioc->Request.Type.Direction == XFER_READ) {
+ /* Copy the data out of the buffer we created */
+ BYTE *ptr = (BYTE *) ioc->buf;
+ for(i=0; i< 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<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;
}
--- linux-2.5.63/include/linux/cciss_ioctl.h~bigioctl 2003-02-27 14:11:56.000000000 +0600
+++ linux-2.5.63-scameron/include/linux/cciss_ioctl.h 2003-02-27 14:11:56.000000000 +0600
@@ -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; /* < MAX_KMALLOC_SIZE in cciss.c */
+ DWORD buf_size; /* size in bytes of the buf */
+ /* < 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
_
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:33    [W:0.025 / U:2.056 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site