X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fscsi%2Faacraid%2Fcommctrl.c;h=36ae4af396ee203c8245f9d06d9ea9fcad3b20af;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=6af1ec0ea3419e66173dd04e20593f8d77765494;hpb=db216c3d5e4c040e557a50f8f5d35d5c415e8c1c;p=linux-2.6.git diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 6af1ec0ea..36ae4af39 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -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_reply* user_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, void* arg) +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;