VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / scsi / aacraid / commctrl.c
index 6af1ec0..36ae4af 100644 (file)
@@ -52,7 +52,7 @@
  *     program.
  */
  
-static int ioctl_send_fib(struct aac_dev * dev, void *arg)
+static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
 {
        struct hw_fib * kfib;
        struct fib *fibptr;
@@ -92,11 +92,12 @@ static int ioctl_send_fib(struct aac_dev * dev, void *arg)
                 */
                kfib->header.XferState = 0;
        } else {
-               if (fib_send(kfib->header.Command, fibptr, le32_to_cpu(kfib->header.Size) , FsaNormal,
-                       1, 1, NULL, NULL) != 0) 
-               {
+               int retval = fib_send(kfib->header.Command, fibptr,
+                               le32_to_cpu(kfib->header.Size) , FsaNormal,
+                               1, 1, NULL, NULL);
+               if (retval) {
                        fib_free(fibptr);
-                       return -EINVAL;
+                       return retval;
                }
                if (fib_complete(fibptr) != 0) {
                        fib_free(fibptr);
@@ -126,18 +127,28 @@ static int ioctl_send_fib(struct aac_dev * dev, void *arg)
  *     passed in from the user.
  */
 
-static int open_getadapter_fib(struct aac_dev * dev, void *arg)
+static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
 {
        struct aac_fib_context * fibctx;
        int status;
-       unsigned long flags;
 
        fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL);
        if (fibctx == NULL) {
                status = -ENOMEM;
        } else {
+               unsigned long flags;
+               struct list_head * entry;
+               struct aac_fib_context * context;
+
                fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;
                fibctx->size = sizeof(struct aac_fib_context);
+               /*
+                *      Yes yes, I know this could be an index, but we have a
+                * better guarantee of uniqueness for the locked loop below.
+                * Without the aid of a persistent history, this also helps
+                * reduce the chance that the opaque context would be reused.
+                */
+               fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF);
                /*
                 *      Initialize the mutex used to wait for the next AIF.
                 */
@@ -155,9 +166,22 @@ static int open_getadapter_fib(struct aac_dev * dev, void *arg)
                 *      AdapterFibContext list.
                 */
                spin_lock_irqsave(&dev->fib_lock, flags);
+               /* Ensure that we have a unique identifier */
+               entry = dev->fib_list.next;
+               while (entry != &dev->fib_list) {
+                       context = list_entry(entry, struct aac_fib_context, next);
+                       if (context->unique == fibctx->unique) {
+                               /* Not unique (32 bits) */
+                               fibctx->unique++;
+                               entry = dev->fib_list.next;
+                       } else {
+                               entry = entry->next;
+                       }
+               }
                list_add_tail(&fibctx->next, &dev->fib_list);
                spin_unlock_irqrestore(&dev->fib_lock, flags);
-               if (copy_to_user(arg,  &fibctx, sizeof(struct aac_fib_context *))) {
+               if (copy_to_user(arg,  &fibctx->unique, 
+                                               sizeof(fibctx->unique))) {
                        status = -EFAULT;
                } else {
                        status = 0;
@@ -175,46 +199,47 @@ static int open_getadapter_fib(struct aac_dev * dev, void *arg)
  *     passed in from the user.
  */
 
-static int next_getadapter_fib(struct aac_dev * dev, void *arg)
+static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
 {
        struct fib_ioctl f;
-       struct aac_fib_context *fibctx, *aifcp;
        struct fib *fib;
+       struct aac_fib_context *fibctx;
        int status;
        struct list_head * entry;
-       int found;
        unsigned long flags;
        
        if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))
                return -EFAULT;
-       /*
-        *      Extract the AdapterFibContext from the Input parameters.
-        */
-       fibctx = (struct aac_fib_context *) f.fibctx;
-
        /*
         *      Verify that the HANDLE passed in was a valid AdapterFibContext
         *
         *      Search the list of AdapterFibContext addresses on the adapter
         *      to be sure this is a valid address
         */
-       found = 0;
        entry = dev->fib_list.next;
+       fibctx = NULL;
 
-       while(entry != &dev->fib_list) {
-               aifcp = list_entry(entry, struct aac_fib_context, next);
-               if(fibctx == aifcp) {   /* We found a winner */
-                       found = 1;
+       while (entry != &dev->fib_list) {
+               fibctx = list_entry(entry, struct aac_fib_context, next);
+               /*
+                *      Extract the AdapterFibContext from the Input parameters.
+                */
+               if (fibctx->unique == f.fibctx) {   /* We found a winner */
                        break;
                }
                entry = entry->next;
+               fibctx = NULL;
        }
-       if (found == 0)
+       if (!fibctx) {
+               dprintk ((KERN_INFO "Fib Context not found\n"));
                return -EINVAL;
+       }
 
        if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
-                (fibctx->size != sizeof(struct aac_fib_context)))
+                (fibctx->size != sizeof(struct aac_fib_context))) {
+               dprintk ((KERN_INFO "Fib Context corrupt?\n"));
                return -EINVAL;
+       }
        status = 0;
        spin_lock_irqsave(&dev->fib_lock, flags);
        /*
@@ -307,18 +332,12 @@ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
  *     This routine will close down the fibctx passed in from the user.
  */
  
-static int close_getadapter_fib(struct aac_dev * dev, void *arg)
+static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
 {
-       struct aac_fib_context *fibctx, *aifcp;
+       struct aac_fib_context *fibctx;
        int status;
        unsigned long flags;
        struct list_head * entry;
-       int found;
-
-       /*
-        *      Extract the fibctx from the input parameters
-        */
-       fibctx = arg;
 
        /*
         *      Verify that the HANDLE passed in was a valid AdapterFibContext
@@ -327,19 +346,23 @@ static int close_getadapter_fib(struct aac_dev * dev, void *arg)
         *      to be sure this is a valid address
         */
 
-       found = 0;
        entry = dev->fib_list.next;
+       fibctx = NULL;
 
        while(entry != &dev->fib_list) {
-               aifcp = list_entry(entry, struct aac_fib_context, next);
-               if(fibctx == aifcp) {   /* We found a winner */
-                       found = 1;
+               fibctx = list_entry(entry, struct aac_fib_context, next);
+               /*
+                *      Extract the fibctx from the input parameters
+                */
+               if (fibctx->unique == (u32)(unsigned long)arg) {   
+                       /* We found a winner */
                        break;
                }
                entry = entry->next;
+               fibctx = NULL;
        }
 
-       if(found == 0)
+       if (!fibctx)
                return 0; /* Already gone */
 
        if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
@@ -356,11 +379,12 @@ static int close_getadapter_fib(struct aac_dev * dev, void *arg)
  *     @dev: adapter
  *     @arg: ioctl arguments
  *
- *     This routine returns the firmware version.
- *      Under Linux, there have been no version incompatibilities, so this is simple!
+ *     This routine returns the driver version.
+ *      Under Linux, there have been no version incompatibilities, so this is 
+ *      simple!
  */
 
-static int check_revision(struct aac_dev *dev, void *arg)
+static int check_revision(struct aac_dev *dev, void __user *arg)
 {
        struct revision response;
 
@@ -379,20 +403,20 @@ static int check_revision(struct aac_dev *dev, void *arg)
  *
  */
 
-int aac_send_raw_srb(struct aac_dev* dev, void* arg)
+int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 {
        struct fib* srbfib;
        int status;
        struct aac_srb *srbcmd;
-       struct aac_srb *user_srb = arg;
-       struct aac_srb_replyuser_reply;
+       struct aac_srb __user *user_srb = arg;
+       struct aac_srb_reply __user *user_reply;
        struct aac_srb_reply* reply;
        u32 fibsize = 0;
        u32 flags = 0;
        s32 rcode = 0;
        u32 data_dir;
-       ulong sg_user[32];
-       ulong sg_list[32];
+       void __user *sg_user[32];
+       void *sg_list[32];
        u32   sg_indx = 0;
        u32 byte_count = 0;
        u32 actual_fibsize = 0;
@@ -413,12 +437,17 @@ int aac_send_raw_srb(struct aac_dev* dev, void* arg)
 
        srbcmd = (struct aac_srb*) fib_data(srbfib);
 
-       if(copy_from_user((void*)&fibsize, (void*)&user_srb->count,sizeof(u32))){
+       if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){
                printk(KERN_DEBUG"aacraid: Could not copy data size from user\n"); 
                rcode = -EFAULT;
                goto cleanup;
        }
 
+       if (fibsize > FIB_DATA_SIZE_IN_BYTES) {
+               rcode = -EINVAL;
+               goto cleanup;
+       }
+
        if(copy_from_user(srbcmd, user_srb,fibsize)){
                printk(KERN_DEBUG"aacraid: Could not copy srb from user\n"); 
                rcode = -EFAULT;
@@ -431,14 +460,14 @@ int aac_send_raw_srb(struct aac_dev* dev, void* arg)
        // Fix up srb for endian and force some values
        srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);       // Force this
        srbcmd->channel  = cpu_to_le32(srbcmd->channel);
-       srbcmd->target   = cpu_to_le32(srbcmd->target);
+       srbcmd->id       = cpu_to_le32(srbcmd->id);
        srbcmd->lun      = cpu_to_le32(srbcmd->lun);
        srbcmd->flags    = cpu_to_le32(srbcmd->flags);
        srbcmd->timeout  = cpu_to_le32(srbcmd->timeout);
        srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter
        srbcmd->cdb_size = cpu_to_le32(srbcmd->cdb_size);
        
-       switch(srbcmd->flags){
+       switch (srbcmd->flags & (SRB_DataIn | SRB_DataOut)) {
        case SRB_DataOut:
                data_dir = DMA_TO_DEVICE;
                break;
@@ -451,17 +480,26 @@ int aac_send_raw_srb(struct aac_dev* dev, void* arg)
        default:
                data_dir = DMA_NONE;
        }
-       if( dev->pae_support ==1 ) {
+       if (dev->pae_support == 1) {
                struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg;
                byte_count = 0;
 
-               // This should also catch if user used the 32 bit sgmap
-               actual_fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry64));
+               /*
+                * This should also catch if user used the 32 bit sgmap
+                */
+               actual_fibsize = sizeof(struct aac_srb) - 
+                       sizeof(struct sgentry) + ((srbcmd->sg.count & 0xff) * 
+                               sizeof(struct sgentry64));
                if(actual_fibsize != fibsize){ // User made a mistake - should not continue
                        printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
                        rcode = -EINVAL;
                        goto cleanup;
                }
+               if ((data_dir == DMA_NONE) && psg->count) { 
+                       printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
+                       rcode = -EINVAL;
+                       goto cleanup;
+               }
 
                for (i = 0; i < psg->count; i++) {
                        dma_addr_t addr; 
@@ -474,12 +512,12 @@ int aac_send_raw_srb(struct aac_dev* dev, void* arg)
                                rcode = -ENOMEM;
                                goto cleanup;
                        }
-                       sg_user[i] = (ulong)psg->sg[i].addr;
-                       sg_list[i] = (ulong)p; // save so we can clean up later
+                       sg_user[i] = (void __user *)psg->sg[i].addr;
+                       sg_list[i] = p; // save so we can clean up later
                        sg_indx = i;
 
                        if( flags & SRB_DataOut ){
-                               if(copy_from_user(p,psg->sg[i].addr,psg->sg[i].count)){
+                               if(copy_from_user(p,sg_user[i],psg->sg[i].count)){
                                        printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
                                        rcode = -EFAULT;
                                        goto cleanup;
@@ -495,7 +533,7 @@ int aac_send_raw_srb(struct aac_dev* dev, void* arg)
                }
 
                srbcmd->count = cpu_to_le32(byte_count);
-               status = fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,0,0);
+               status = fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL);
        } else {
                struct sgmap* psg = &srbcmd->sg;
                byte_count = 0;
@@ -506,6 +544,11 @@ int aac_send_raw_srb(struct aac_dev* dev, void* arg)
                        rcode = -EINVAL;
                        goto cleanup;
                }
+               if ((data_dir == DMA_NONE) && psg->count) {
+                       printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
+                       rcode = -EINVAL;
+                       goto cleanup;
+               }
                for (i = 0; i < psg->count; i++) {
                        dma_addr_t addr; 
                        void* p;
@@ -516,12 +559,12 @@ int aac_send_raw_srb(struct aac_dev* dev, void* arg)
                                rcode = -ENOMEM;
                                goto cleanup;
                        }
-                       sg_user[i] = (ulong)(psg->sg[i].addr);
-                       sg_list[i] = (ulong)p; // save so we can clean up later
+                       sg_user[i] = (void __user *)(psg->sg[i].addr);
+                       sg_list[i] = p; // save so we can clean up later
                        sg_indx = i;
 
                        if( flags & SRB_DataOut ){
-                               if(copy_from_user((void*)p,(void*)(ulong)(psg->sg[i].addr),psg->sg[i].count)){
+                               if(copy_from_user(p,sg_user[i],psg->sg[i].count)){
                                        printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
                                        rcode = -EFAULT;
                                        goto cleanup;
@@ -534,7 +577,7 @@ int aac_send_raw_srb(struct aac_dev* dev, void* arg)
                        byte_count += psg->sg[i].count;
                }
                srbcmd->count = cpu_to_le32(byte_count);
-               status = fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, 0, 0);
+               status = fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL);
        }
 
        if (status != 0){
@@ -545,7 +588,7 @@ int aac_send_raw_srb(struct aac_dev* dev, void* arg)
 
        if( flags & SRB_DataIn ) {
                for(i = 0 ; i <= sg_indx; i++){
-                       if(copy_to_user((void*)(sg_user[i]),(void*)(sg_list[i]),le32_to_cpu(srbcmd->sg.sg[i].count))){
+                       if(copy_to_user(sg_user[i],sg_list[i],le32_to_cpu(srbcmd->sg.sg[i].count))){
                                printk(KERN_DEBUG"aacraid: Could not copy sg data to user\n"); 
                                rcode = -EFAULT;
                                goto cleanup;
@@ -563,7 +606,7 @@ int aac_send_raw_srb(struct aac_dev* dev, void* arg)
 
 cleanup:
        for(i=0; i <= sg_indx; i++){
-               kfree((void*)sg_list[i]);
+               kfree(sg_list[i]);
        }
        fib_complete(srbfib);
        fib_free(srbfib);
@@ -578,14 +621,14 @@ struct aac_pci_info {
 };
 
 
-int aac_get_pci_info(struct aac_dev* dev, voidarg)
+int aac_get_pci_info(struct aac_dev* dev, void __user *arg)
 {
         struct aac_pci_info pci_info;
 
        pci_info.bus = dev->pdev->bus->number;
        pci_info.slot = PCI_SLOT(dev->pdev->devfn);
 
-       if(copy_to_user( arg, (void*)&pci_info, sizeof(struct aac_pci_info))){
+       if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
                printk(KERN_DEBUG "aacraid: Could not copy pci info\n");
                return -EFAULT;
        }
@@ -593,7 +636,7 @@ int aac_get_pci_info(struct aac_dev* dev, void* arg)
  }
  
 
-int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg)
+int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
 {
        int status;