diff options
Diffstat (limited to 'drivers/scsi/aacraid')
-rw-r--r-- | drivers/scsi/aacraid/commctrl.c | 259 |
1 files changed, 157 insertions, 102 deletions
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 3a8e7cac9ee2..987e35e4078e 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * based on the old aacraid driver that is.. | 5 | * based on the old aacraid driver that is.. |
6 | * Adaptec aacraid device driver for Linux. | 6 | * Adaptec aacraid device driver for Linux. |
7 | * | 7 | * |
8 | * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) | 8 | * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -468,7 +468,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) | |||
468 | void *sg_list[32]; | 468 | void *sg_list[32]; |
469 | u32 sg_indx = 0; | 469 | u32 sg_indx = 0; |
470 | u32 byte_count = 0; | 470 | u32 byte_count = 0; |
471 | u32 actual_fibsize = 0; | 471 | u32 actual_fibsize64, actual_fibsize = 0; |
472 | int i; | 472 | int i; |
473 | 473 | ||
474 | 474 | ||
@@ -481,7 +481,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) | |||
481 | return -EPERM; | 481 | return -EPERM; |
482 | } | 482 | } |
483 | /* | 483 | /* |
484 | * Allocate and initialize a Fib then setup a BlockWrite command | 484 | * Allocate and initialize a Fib then setup a SRB command |
485 | */ | 485 | */ |
486 | if (!(srbfib = aac_fib_alloc(dev))) { | 486 | if (!(srbfib = aac_fib_alloc(dev))) { |
487 | return -ENOMEM; | 487 | return -ENOMEM; |
@@ -548,129 +548,183 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) | |||
548 | rcode = -EINVAL; | 548 | rcode = -EINVAL; |
549 | goto cleanup; | 549 | goto cleanup; |
550 | } | 550 | } |
551 | if (dev->dac_support == 1) { | 551 | actual_fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) + |
552 | ((user_srbcmd->sg.count & 0xff) * sizeof(struct sgentry)); | ||
553 | actual_fibsize64 = actual_fibsize + (user_srbcmd->sg.count & 0xff) * | ||
554 | (sizeof(struct sgentry64) - sizeof(struct sgentry)); | ||
555 | /* User made a mistake - should not continue */ | ||
556 | if ((actual_fibsize != fibsize) && (actual_fibsize64 != fibsize)) { | ||
557 | dprintk((KERN_DEBUG"aacraid: Bad Size specified in " | ||
558 | "Raw SRB command calculated fibsize=%lu;%lu " | ||
559 | "user_srbcmd->sg.count=%d aac_srb=%lu sgentry=%lu;%lu " | ||
560 | "issued fibsize=%d\n", | ||
561 | actual_fibsize, actual_fibsize64, user_srbcmd->sg.count, | ||
562 | sizeof(struct aac_srb), sizeof(struct sgentry), | ||
563 | sizeof(struct sgentry64), fibsize)); | ||
564 | rcode = -EINVAL; | ||
565 | goto cleanup; | ||
566 | } | ||
567 | if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) { | ||
568 | dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n")); | ||
569 | rcode = -EINVAL; | ||
570 | goto cleanup; | ||
571 | } | ||
572 | byte_count = 0; | ||
573 | if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) { | ||
552 | struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg; | 574 | struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg; |
553 | struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg; | 575 | struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg; |
554 | struct user_sgmap* usg; | ||
555 | byte_count = 0; | ||
556 | 576 | ||
557 | /* | 577 | /* |
558 | * This should also catch if user used the 32 bit sgmap | 578 | * This should also catch if user used the 32 bit sgmap |
559 | */ | 579 | */ |
560 | actual_fibsize = sizeof(struct aac_srb) - | 580 | if (actual_fibsize64 == fibsize) { |
561 | sizeof(struct sgentry) + | 581 | actual_fibsize = actual_fibsize64; |
562 | ((upsg->count & 0xff) * | 582 | for (i = 0; i < upsg->count; i++) { |
563 | sizeof(struct sgentry)); | 583 | u64 addr; |
564 | if(actual_fibsize != fibsize){ // User made a mistake - should not continue | 584 | void* p; |
565 | dprintk((KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n")); | 585 | /* Does this really need to be GFP_DMA? */ |
566 | rcode = -EINVAL; | 586 | p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA); |
567 | goto cleanup; | 587 | if(p == 0) { |
568 | } | 588 | dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", |
569 | usg = kmalloc(actual_fibsize - sizeof(struct aac_srb) | 589 | upsg->sg[i].count,i,upsg->count)); |
570 | + sizeof(struct sgmap), GFP_KERNEL); | 590 | rcode = -ENOMEM; |
571 | if (!usg) { | 591 | goto cleanup; |
572 | dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n")); | 592 | } |
573 | rcode = -ENOMEM; | 593 | addr = (u64)upsg->sg[i].addr[0]; |
574 | goto cleanup; | 594 | addr += ((u64)upsg->sg[i].addr[1]) << 32; |
575 | } | 595 | sg_user[i] = (void __user *)(ptrdiff_t)addr; |
576 | memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb) | 596 | sg_list[i] = p; // save so we can clean up later |
577 | + sizeof(struct sgmap)); | 597 | sg_indx = i; |
578 | actual_fibsize = sizeof(struct aac_srb) - | 598 | |
579 | sizeof(struct sgentry) + ((usg->count & 0xff) * | 599 | if( flags & SRB_DataOut ){ |
580 | sizeof(struct sgentry64)); | 600 | if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ |
581 | if ((data_dir == DMA_NONE) && upsg->count) { | 601 | dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); |
582 | kfree (usg); | 602 | rcode = -EFAULT; |
583 | dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n")); | 603 | goto cleanup; |
584 | rcode = -EINVAL; | 604 | } |
585 | goto cleanup; | 605 | } |
586 | } | 606 | addr = pci_map_single(dev->pdev, p, upsg->sg[i].count, data_dir); |
587 | 607 | ||
588 | for (i = 0; i < usg->count; i++) { | 608 | psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); |
589 | u64 addr; | 609 | psg->sg[i].addr[1] = cpu_to_le32(addr>>32); |
590 | void* p; | 610 | byte_count += upsg->sg[i].count; |
591 | /* Does this really need to be GFP_DMA? */ | 611 | psg->sg[i].count = cpu_to_le32(upsg->sg[i].count); |
592 | p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); | 612 | } |
593 | if(p == 0) { | 613 | } else { |
594 | kfree (usg); | 614 | struct user_sgmap* usg; |
595 | dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", | 615 | usg = kmalloc(actual_fibsize - sizeof(struct aac_srb) |
596 | usg->sg[i].count,i,usg->count)); | 616 | + sizeof(struct sgmap), GFP_KERNEL); |
617 | if (!usg) { | ||
618 | dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n")); | ||
597 | rcode = -ENOMEM; | 619 | rcode = -ENOMEM; |
598 | goto cleanup; | 620 | goto cleanup; |
599 | } | 621 | } |
600 | sg_user[i] = (void __user *)(long)usg->sg[i].addr; | 622 | memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb) |
601 | sg_list[i] = p; // save so we can clean up later | 623 | + sizeof(struct sgmap)); |
602 | sg_indx = i; | 624 | actual_fibsize = actual_fibsize64; |
603 | 625 | ||
604 | if( flags & SRB_DataOut ){ | 626 | for (i = 0; i < usg->count; i++) { |
605 | if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ | 627 | u64 addr; |
628 | void* p; | ||
629 | /* Does this really need to be GFP_DMA? */ | ||
630 | p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); | ||
631 | if(p == 0) { | ||
606 | kfree (usg); | 632 | kfree (usg); |
607 | dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); | 633 | dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", |
608 | rcode = -EFAULT; | 634 | usg->sg[i].count,i,usg->count)); |
635 | rcode = -ENOMEM; | ||
609 | goto cleanup; | 636 | goto cleanup; |
610 | } | 637 | } |
611 | } | 638 | sg_user[i] = (void __user *)(ptrdiff_t)usg->sg[i].addr; |
612 | addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir); | 639 | sg_list[i] = p; // save so we can clean up later |
640 | sg_indx = i; | ||
641 | |||
642 | if( flags & SRB_DataOut ){ | ||
643 | if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ | ||
644 | kfree (usg); | ||
645 | dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); | ||
646 | rcode = -EFAULT; | ||
647 | goto cleanup; | ||
648 | } | ||
649 | } | ||
650 | addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir); | ||
613 | 651 | ||
614 | psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); | 652 | psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); |
615 | psg->sg[i].addr[1] = cpu_to_le32(addr>>32); | 653 | psg->sg[i].addr[1] = cpu_to_le32(addr>>32); |
616 | psg->sg[i].count = cpu_to_le32(usg->sg[i].count); | 654 | byte_count += usg->sg[i].count; |
617 | byte_count += usg->sg[i].count; | 655 | psg->sg[i].count = cpu_to_le32(usg->sg[i].count); |
656 | } | ||
657 | kfree (usg); | ||
618 | } | 658 | } |
619 | kfree (usg); | ||
620 | |||
621 | srbcmd->count = cpu_to_le32(byte_count); | 659 | srbcmd->count = cpu_to_le32(byte_count); |
622 | psg->count = cpu_to_le32(sg_indx+1); | 660 | psg->count = cpu_to_le32(sg_indx+1); |
623 | status = aac_fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL); | 661 | status = aac_fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL); |
624 | } else { | 662 | } else { |
625 | struct user_sgmap* upsg = &user_srbcmd->sg; | 663 | struct user_sgmap* upsg = &user_srbcmd->sg; |
626 | struct sgmap* psg = &srbcmd->sg; | 664 | struct sgmap* psg = &srbcmd->sg; |
627 | byte_count = 0; | 665 | |
628 | 666 | if (actual_fibsize64 == fibsize) { | |
629 | actual_fibsize = sizeof (struct aac_srb) + (((user_srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry)); | 667 | struct user_sgmap64* usg = (struct user_sgmap64 *)upsg; |
630 | if(actual_fibsize != fibsize){ // User made a mistake - should not continue | 668 | for (i = 0; i < upsg->count; i++) { |
631 | dprintk((KERN_DEBUG"aacraid: Bad Size specified in " | 669 | u64 addr; |
632 | "Raw SRB command calculated fibsize=%d " | 670 | void* p; |
633 | "user_srbcmd->sg.count=%d aac_srb=%d sgentry=%d " | 671 | /* Does this really need to be GFP_DMA? */ |
634 | "issued fibsize=%d\n", | 672 | p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); |
635 | actual_fibsize, user_srbcmd->sg.count, | 673 | if(p == 0) { |
636 | sizeof(struct aac_srb), sizeof(struct sgentry), | 674 | dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", |
637 | fibsize)); | 675 | usg->sg[i].count,i,usg->count)); |
638 | rcode = -EINVAL; | 676 | rcode = -ENOMEM; |
639 | goto cleanup; | ||
640 | } | ||
641 | if ((data_dir == DMA_NONE) && upsg->count) { | ||
642 | dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n")); | ||
643 | rcode = -EINVAL; | ||
644 | goto cleanup; | ||
645 | } | ||
646 | for (i = 0; i < upsg->count; i++) { | ||
647 | dma_addr_t addr; | ||
648 | void* p; | ||
649 | p = kmalloc(upsg->sg[i].count, GFP_KERNEL); | ||
650 | if(p == 0) { | ||
651 | dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", | ||
652 | upsg->sg[i].count, i, upsg->count)); | ||
653 | rcode = -ENOMEM; | ||
654 | goto cleanup; | ||
655 | } | ||
656 | sg_user[i] = (void __user *)(long)upsg->sg[i].addr; | ||
657 | sg_list[i] = p; // save so we can clean up later | ||
658 | sg_indx = i; | ||
659 | |||
660 | if( flags & SRB_DataOut ){ | ||
661 | if(copy_from_user(p, sg_user[i], | ||
662 | upsg->sg[i].count)) { | ||
663 | dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); | ||
664 | rcode = -EFAULT; | ||
665 | goto cleanup; | 677 | goto cleanup; |
666 | } | 678 | } |
679 | addr = (u64)usg->sg[i].addr[0]; | ||
680 | addr += ((u64)usg->sg[i].addr[1]) << 32; | ||
681 | sg_user[i] = (void __user *)(ptrdiff_t)addr; | ||
682 | sg_list[i] = p; // save so we can clean up later | ||
683 | sg_indx = i; | ||
684 | |||
685 | if( flags & SRB_DataOut ){ | ||
686 | if(copy_from_user(p,sg_user[i],usg->sg[i].count)){ | ||
687 | dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); | ||
688 | rcode = -EFAULT; | ||
689 | goto cleanup; | ||
690 | } | ||
691 | } | ||
692 | addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir); | ||
693 | |||
694 | psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff); | ||
695 | byte_count += usg->sg[i].count; | ||
696 | psg->sg[i].count = cpu_to_le32(usg->sg[i].count); | ||
667 | } | 697 | } |
668 | addr = pci_map_single(dev->pdev, p, | 698 | } else { |
669 | upsg->sg[i].count, data_dir); | 699 | for (i = 0; i < upsg->count; i++) { |
700 | dma_addr_t addr; | ||
701 | void* p; | ||
702 | p = kmalloc(upsg->sg[i].count, GFP_KERNEL); | ||
703 | if(p == 0) { | ||
704 | dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", | ||
705 | upsg->sg[i].count, i, upsg->count)); | ||
706 | rcode = -ENOMEM; | ||
707 | goto cleanup; | ||
708 | } | ||
709 | sg_user[i] = (void __user *)(ptrdiff_t)upsg->sg[i].addr; | ||
710 | sg_list[i] = p; // save so we can clean up later | ||
711 | sg_indx = i; | ||
712 | |||
713 | if( flags & SRB_DataOut ){ | ||
714 | if(copy_from_user(p, sg_user[i], | ||
715 | upsg->sg[i].count)) { | ||
716 | dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); | ||
717 | rcode = -EFAULT; | ||
718 | goto cleanup; | ||
719 | } | ||
720 | } | ||
721 | addr = pci_map_single(dev->pdev, p, | ||
722 | upsg->sg[i].count, data_dir); | ||
670 | 723 | ||
671 | psg->sg[i].addr = cpu_to_le32(addr); | 724 | psg->sg[i].addr = cpu_to_le32(addr); |
672 | psg->sg[i].count = cpu_to_le32(upsg->sg[i].count); | 725 | byte_count += upsg->sg[i].count; |
673 | byte_count += upsg->sg[i].count; | 726 | psg->sg[i].count = cpu_to_le32(upsg->sg[i].count); |
727 | } | ||
674 | } | 728 | } |
675 | srbcmd->count = cpu_to_le32(byte_count); | 729 | srbcmd->count = cpu_to_le32(byte_count); |
676 | psg->count = cpu_to_le32(sg_indx+1); | 730 | psg->count = cpu_to_le32(sg_indx+1); |
@@ -689,7 +743,8 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) | |||
689 | 743 | ||
690 | if( flags & SRB_DataIn ) { | 744 | if( flags & SRB_DataIn ) { |
691 | for(i = 0 ; i <= sg_indx; i++){ | 745 | for(i = 0 ; i <= sg_indx; i++){ |
692 | byte_count = le32_to_cpu((dev->dac_support == 1) | 746 | byte_count = le32_to_cpu( |
747 | (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) | ||
693 | ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count | 748 | ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count |
694 | : srbcmd->sg.sg[i].count); | 749 | : srbcmd->sg.sg[i].count); |
695 | if(copy_to_user(sg_user[i], sg_list[i], byte_count)){ | 750 | if(copy_to_user(sg_user[i], sg_list[i], byte_count)){ |