| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /*************************************************************************** |
|---|
| 2 | 3 | dpti.c - description |
|---|
| 3 | 4 | ------------------- |
|---|
| .. | .. |
|---|
| 7 | 8 | July 30, 2001 First version being submitted |
|---|
| 8 | 9 | for inclusion in the kernel. V2.4 |
|---|
| 9 | 10 | |
|---|
| 10 | | - See Documentation/scsi/dpti.txt for history, notes, license info |
|---|
| 11 | + See Documentation/scsi/dpti.rst for history, notes, license info |
|---|
| 11 | 12 | and credits |
|---|
| 12 | 13 | ***************************************************************************/ |
|---|
| 13 | 14 | |
|---|
| 14 | 15 | /*************************************************************************** |
|---|
| 15 | 16 | * * |
|---|
| 16 | | - * This program is free software; you can redistribute it and/or modify * |
|---|
| 17 | | - * it under the terms of the GNU General Public License as published by * |
|---|
| 18 | | - * the Free Software Foundation; either version 2 of the License, or * |
|---|
| 19 | | - * (at your option) any later version. * |
|---|
| 20 | 17 | * * |
|---|
| 21 | 18 | ***************************************************************************/ |
|---|
| 22 | 19 | /*************************************************************************** |
|---|
| .. | .. |
|---|
| 30 | 27 | /*#define UARTDELAY 1 */ |
|---|
| 31 | 28 | |
|---|
| 32 | 29 | #include <linux/module.h> |
|---|
| 30 | +#include <linux/pgtable.h> |
|---|
| 33 | 31 | |
|---|
| 34 | 32 | MODULE_AUTHOR("Deanna Bonds, with _lots_ of help from Mark Salyzyn"); |
|---|
| 35 | 33 | MODULE_DESCRIPTION("Adaptec I2O RAID Driver"); |
|---|
| .. | .. |
|---|
| 58 | 56 | #include <linux/mutex.h> |
|---|
| 59 | 57 | |
|---|
| 60 | 58 | #include <asm/processor.h> /* for boot_cpu_data */ |
|---|
| 61 | | -#include <asm/pgtable.h> |
|---|
| 62 | | -#include <asm/io.h> /* for virt_to_bus, etc. */ |
|---|
| 59 | +#include <asm/io.h> |
|---|
| 63 | 60 | |
|---|
| 64 | 61 | #include <scsi/scsi.h> |
|---|
| 65 | 62 | #include <scsi/scsi_cmnd.h> |
|---|
| .. | .. |
|---|
| 411 | 408 | static int adpt_slave_configure(struct scsi_device * device) |
|---|
| 412 | 409 | { |
|---|
| 413 | 410 | struct Scsi_Host *host = device->host; |
|---|
| 414 | | - adpt_hba* pHba; |
|---|
| 415 | | - |
|---|
| 416 | | - pHba = (adpt_hba *) host->hostdata[0]; |
|---|
| 417 | 411 | |
|---|
| 418 | 412 | if (host->can_queue && device->tagged_supported) { |
|---|
| 419 | 413 | scsi_change_queue_depth(device, |
|---|
| .. | .. |
|---|
| 588 | 582 | return 0; |
|---|
| 589 | 583 | } |
|---|
| 590 | 584 | |
|---|
| 591 | | -/* |
|---|
| 592 | | - * Turn a struct scsi_cmnd * into a unique 32 bit 'context'. |
|---|
| 593 | | - */ |
|---|
| 594 | | -static u32 adpt_cmd_to_context(struct scsi_cmnd *cmd) |
|---|
| 595 | | -{ |
|---|
| 596 | | - return (u32)cmd->serial_number; |
|---|
| 597 | | -} |
|---|
| 598 | | - |
|---|
| 599 | | -/* |
|---|
| 600 | | - * Go from a u32 'context' to a struct scsi_cmnd * . |
|---|
| 601 | | - * This could probably be made more efficient. |
|---|
| 602 | | - */ |
|---|
| 603 | | -static struct scsi_cmnd * |
|---|
| 604 | | - adpt_cmd_from_context(adpt_hba * pHba, u32 context) |
|---|
| 605 | | -{ |
|---|
| 606 | | - struct scsi_cmnd * cmd; |
|---|
| 607 | | - struct scsi_device * d; |
|---|
| 608 | | - |
|---|
| 609 | | - if (context == 0) |
|---|
| 610 | | - return NULL; |
|---|
| 611 | | - |
|---|
| 612 | | - spin_unlock(pHba->host->host_lock); |
|---|
| 613 | | - shost_for_each_device(d, pHba->host) { |
|---|
| 614 | | - unsigned long flags; |
|---|
| 615 | | - spin_lock_irqsave(&d->list_lock, flags); |
|---|
| 616 | | - list_for_each_entry(cmd, &d->cmd_list, list) { |
|---|
| 617 | | - if (((u32)cmd->serial_number == context)) { |
|---|
| 618 | | - spin_unlock_irqrestore(&d->list_lock, flags); |
|---|
| 619 | | - scsi_device_put(d); |
|---|
| 620 | | - spin_lock(pHba->host->host_lock); |
|---|
| 621 | | - return cmd; |
|---|
| 622 | | - } |
|---|
| 623 | | - } |
|---|
| 624 | | - spin_unlock_irqrestore(&d->list_lock, flags); |
|---|
| 625 | | - } |
|---|
| 626 | | - spin_lock(pHba->host->host_lock); |
|---|
| 627 | | - |
|---|
| 628 | | - return NULL; |
|---|
| 629 | | -} |
|---|
| 630 | | - |
|---|
| 631 | | -/* |
|---|
| 632 | | - * Turn a pointer to ioctl reply data into an u32 'context' |
|---|
| 633 | | - */ |
|---|
| 634 | | -static u32 adpt_ioctl_to_context(adpt_hba * pHba, void *reply) |
|---|
| 635 | | -{ |
|---|
| 636 | | -#if BITS_PER_LONG == 32 |
|---|
| 637 | | - return (u32)(unsigned long)reply; |
|---|
| 638 | | -#else |
|---|
| 639 | | - ulong flags = 0; |
|---|
| 640 | | - u32 nr, i; |
|---|
| 641 | | - |
|---|
| 642 | | - spin_lock_irqsave(pHba->host->host_lock, flags); |
|---|
| 643 | | - nr = ARRAY_SIZE(pHba->ioctl_reply_context); |
|---|
| 644 | | - for (i = 0; i < nr; i++) { |
|---|
| 645 | | - if (pHba->ioctl_reply_context[i] == NULL) { |
|---|
| 646 | | - pHba->ioctl_reply_context[i] = reply; |
|---|
| 647 | | - break; |
|---|
| 648 | | - } |
|---|
| 649 | | - } |
|---|
| 650 | | - spin_unlock_irqrestore(pHba->host->host_lock, flags); |
|---|
| 651 | | - if (i >= nr) { |
|---|
| 652 | | - printk(KERN_WARNING"%s: Too many outstanding " |
|---|
| 653 | | - "ioctl commands\n", pHba->name); |
|---|
| 654 | | - return (u32)-1; |
|---|
| 655 | | - } |
|---|
| 656 | | - |
|---|
| 657 | | - return i; |
|---|
| 658 | | -#endif |
|---|
| 659 | | -} |
|---|
| 660 | | - |
|---|
| 661 | | -/* |
|---|
| 662 | | - * Go from an u32 'context' to a pointer to ioctl reply data. |
|---|
| 663 | | - */ |
|---|
| 664 | | -static void *adpt_ioctl_from_context(adpt_hba *pHba, u32 context) |
|---|
| 665 | | -{ |
|---|
| 666 | | -#if BITS_PER_LONG == 32 |
|---|
| 667 | | - return (void *)(unsigned long)context; |
|---|
| 668 | | -#else |
|---|
| 669 | | - void *p = pHba->ioctl_reply_context[context]; |
|---|
| 670 | | - pHba->ioctl_reply_context[context] = NULL; |
|---|
| 671 | | - |
|---|
| 672 | | - return p; |
|---|
| 673 | | -#endif |
|---|
| 674 | | -} |
|---|
| 675 | | - |
|---|
| 676 | 585 | /*=========================================================================== |
|---|
| 677 | 586 | * Error Handling routines |
|---|
| 678 | 587 | *=========================================================================== |
|---|
| .. | .. |
|---|
| 685 | 594 | u32 msg[5]; |
|---|
| 686 | 595 | int rcode; |
|---|
| 687 | 596 | |
|---|
| 688 | | - if(cmd->serial_number == 0){ |
|---|
| 689 | | - return FAILED; |
|---|
| 690 | | - } |
|---|
| 691 | 597 | pHba = (adpt_hba*) cmd->device->host->hostdata[0]; |
|---|
| 692 | 598 | printk(KERN_INFO"%s: Trying to Abort\n",pHba->name); |
|---|
| 693 | 599 | if ((dptdevice = (void*) (cmd->device->hostdata)) == NULL) { |
|---|
| .. | .. |
|---|
| 699 | 605 | msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; |
|---|
| 700 | 606 | msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|dptdevice->tid; |
|---|
| 701 | 607 | msg[2] = 0; |
|---|
| 702 | | - msg[3]= 0; |
|---|
| 703 | | - msg[4] = adpt_cmd_to_context(cmd); |
|---|
| 608 | + msg[3]= 0; |
|---|
| 609 | + /* Add 1 to avoid firmware treating it as invalid command */ |
|---|
| 610 | + msg[4] = cmd->request->tag + 1; |
|---|
| 704 | 611 | if (pHba->host) |
|---|
| 705 | 612 | spin_lock_irq(pHba->host->host_lock); |
|---|
| 706 | 613 | rcode = adpt_i2o_post_wait(pHba, msg, sizeof(msg), FOREVER); |
|---|
| .. | .. |
|---|
| 862 | 769 | } |
|---|
| 863 | 770 | pHba->state &= ~DPTI_STATE_RESET; |
|---|
| 864 | 771 | |
|---|
| 865 | | - adpt_fail_posted_scbs(pHba); |
|---|
| 772 | + scsi_host_complete_all_commands(pHba->host, DID_RESET); |
|---|
| 866 | 773 | return 0; /* return success */ |
|---|
| 867 | 774 | } |
|---|
| 868 | 775 | |
|---|
| .. | .. |
|---|
| 877 | 784 | adpt_hba *pHba, *pNext; |
|---|
| 878 | 785 | struct adpt_i2o_post_wait_data *p1, *old; |
|---|
| 879 | 786 | |
|---|
| 880 | | - printk(KERN_INFO"Shutting down Adaptec I2O controllers.\n"); |
|---|
| 881 | | - printk(KERN_INFO" This could take a few minutes if there are many devices attached\n"); |
|---|
| 787 | + printk(KERN_INFO "Shutting down Adaptec I2O controllers.\n"); |
|---|
| 788 | + printk(KERN_INFO " This could take a few minutes if there are many devices attached\n"); |
|---|
| 882 | 789 | /* Delete all IOPs from the controller chain */ |
|---|
| 883 | 790 | /* They should have already been released by the |
|---|
| 884 | 791 | * scsi-core |
|---|
| .. | .. |
|---|
| 901 | 808 | // spin_unlock_irqrestore(&adpt_post_wait_lock, flags); |
|---|
| 902 | 809 | adpt_post_wait_queue = NULL; |
|---|
| 903 | 810 | |
|---|
| 904 | | - printk(KERN_INFO "Adaptec I2O controllers down.\n"); |
|---|
| 811 | + printk(KERN_INFO "Adaptec I2O controllers down.\n"); |
|---|
| 905 | 812 | } |
|---|
| 906 | 813 | |
|---|
| 907 | 814 | static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev) |
|---|
| .. | .. |
|---|
| 934 | 841 | * See if we should enable dma64 mode. |
|---|
| 935 | 842 | */ |
|---|
| 936 | 843 | if (sizeof(dma_addr_t) > 4 && |
|---|
| 937 | | - pci_set_dma_mask(pDev, DMA_BIT_MASK(64)) == 0) { |
|---|
| 938 | | - if (dma_get_required_mask(&pDev->dev) > DMA_BIT_MASK(32)) |
|---|
| 939 | | - dma64 = 1; |
|---|
| 940 | | - } |
|---|
| 941 | | - if (!dma64 && pci_set_dma_mask(pDev, DMA_BIT_MASK(32)) != 0) |
|---|
| 844 | + dma_get_required_mask(&pDev->dev) > DMA_BIT_MASK(32) && |
|---|
| 845 | + dma_set_mask(&pDev->dev, DMA_BIT_MASK(64)) == 0) |
|---|
| 846 | + dma64 = 1; |
|---|
| 847 | + |
|---|
| 848 | + if (!dma64 && dma_set_mask(&pDev->dev, DMA_BIT_MASK(32)) != 0) |
|---|
| 942 | 849 | return -EINVAL; |
|---|
| 943 | 850 | |
|---|
| 944 | 851 | /* adapter only supports message blocks below 4GB */ |
|---|
| 945 | | - pci_set_consistent_dma_mask(pDev, DMA_BIT_MASK(32)); |
|---|
| 852 | + dma_set_coherent_mask(&pDev->dev, DMA_BIT_MASK(32)); |
|---|
| 946 | 853 | |
|---|
| 947 | 854 | base_addr0_phys = pci_resource_start(pDev,0); |
|---|
| 948 | 855 | hba_map0_area_size = pci_resource_len(pDev,0); |
|---|
| .. | .. |
|---|
| 1165 | 1072 | { |
|---|
| 1166 | 1073 | struct adpt_device* d; |
|---|
| 1167 | 1074 | |
|---|
| 1168 | | - if(chan < 0 || chan >= MAX_CHANNEL) |
|---|
| 1075 | + if (chan >= MAX_CHANNEL) |
|---|
| 1169 | 1076 | return NULL; |
|---|
| 1170 | 1077 | |
|---|
| 1171 | 1078 | d = pHba->channel[chan].device[id]; |
|---|
| .. | .. |
|---|
| 1376 | 1283 | printk(KERN_ERR"IOP reset failed - no free memory.\n"); |
|---|
| 1377 | 1284 | return -ENOMEM; |
|---|
| 1378 | 1285 | } |
|---|
| 1379 | | - memset(status,0,4); |
|---|
| 1380 | 1286 | |
|---|
| 1381 | 1287 | msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0; |
|---|
| 1382 | 1288 | msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID; |
|---|
| .. | .. |
|---|
| 1697 | 1603 | return 0; |
|---|
| 1698 | 1604 | } |
|---|
| 1699 | 1605 | |
|---|
| 1700 | | - |
|---|
| 1701 | | -static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg) |
|---|
| 1702 | | -{ |
|---|
| 1703 | | - u32 msg[MAX_MESSAGE_SIZE]; |
|---|
| 1704 | | - u32* reply = NULL; |
|---|
| 1705 | | - u32 size = 0; |
|---|
| 1706 | | - u32 reply_size = 0; |
|---|
| 1707 | | - u32 __user *user_msg = arg; |
|---|
| 1708 | | - u32 __user * user_reply = NULL; |
|---|
| 1709 | | - void **sg_list = NULL; |
|---|
| 1710 | | - u32 sg_offset = 0; |
|---|
| 1711 | | - u32 sg_count = 0; |
|---|
| 1712 | | - int sg_index = 0; |
|---|
| 1713 | | - u32 i = 0; |
|---|
| 1714 | | - u32 rcode = 0; |
|---|
| 1715 | | - void *p = NULL; |
|---|
| 1716 | | - dma_addr_t addr; |
|---|
| 1717 | | - ulong flags = 0; |
|---|
| 1718 | | - |
|---|
| 1719 | | - memset(&msg, 0, MAX_MESSAGE_SIZE*4); |
|---|
| 1720 | | - // get user msg size in u32s |
|---|
| 1721 | | - if(get_user(size, &user_msg[0])){ |
|---|
| 1722 | | - return -EFAULT; |
|---|
| 1723 | | - } |
|---|
| 1724 | | - size = size>>16; |
|---|
| 1725 | | - |
|---|
| 1726 | | - user_reply = &user_msg[size]; |
|---|
| 1727 | | - if(size > MAX_MESSAGE_SIZE){ |
|---|
| 1728 | | - return -EFAULT; |
|---|
| 1729 | | - } |
|---|
| 1730 | | - size *= 4; // Convert to bytes |
|---|
| 1731 | | - |
|---|
| 1732 | | - /* Copy in the user's I2O command */ |
|---|
| 1733 | | - if(copy_from_user(msg, user_msg, size)) { |
|---|
| 1734 | | - return -EFAULT; |
|---|
| 1735 | | - } |
|---|
| 1736 | | - get_user(reply_size, &user_reply[0]); |
|---|
| 1737 | | - reply_size = reply_size>>16; |
|---|
| 1738 | | - if(reply_size > REPLY_FRAME_SIZE){ |
|---|
| 1739 | | - reply_size = REPLY_FRAME_SIZE; |
|---|
| 1740 | | - } |
|---|
| 1741 | | - reply_size *= 4; |
|---|
| 1742 | | - reply = kzalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL); |
|---|
| 1743 | | - if(reply == NULL) { |
|---|
| 1744 | | - printk(KERN_WARNING"%s: Could not allocate reply buffer\n",pHba->name); |
|---|
| 1745 | | - return -ENOMEM; |
|---|
| 1746 | | - } |
|---|
| 1747 | | - sg_offset = (msg[0]>>4)&0xf; |
|---|
| 1748 | | - msg[2] = 0x40000000; // IOCTL context |
|---|
| 1749 | | - msg[3] = adpt_ioctl_to_context(pHba, reply); |
|---|
| 1750 | | - if (msg[3] == (u32)-1) { |
|---|
| 1751 | | - rcode = -EBUSY; |
|---|
| 1752 | | - goto free; |
|---|
| 1753 | | - } |
|---|
| 1754 | | - |
|---|
| 1755 | | - sg_list = kcalloc(pHba->sg_tablesize, sizeof(*sg_list), GFP_KERNEL); |
|---|
| 1756 | | - if (!sg_list) { |
|---|
| 1757 | | - rcode = -ENOMEM; |
|---|
| 1758 | | - goto free; |
|---|
| 1759 | | - } |
|---|
| 1760 | | - if(sg_offset) { |
|---|
| 1761 | | - // TODO add 64 bit API |
|---|
| 1762 | | - struct sg_simple_element *sg = (struct sg_simple_element*) (msg+sg_offset); |
|---|
| 1763 | | - sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element); |
|---|
| 1764 | | - if (sg_count > pHba->sg_tablesize){ |
|---|
| 1765 | | - printk(KERN_DEBUG"%s:IOCTL SG List too large (%u)\n", pHba->name,sg_count); |
|---|
| 1766 | | - rcode = -EINVAL; |
|---|
| 1767 | | - goto free; |
|---|
| 1768 | | - } |
|---|
| 1769 | | - |
|---|
| 1770 | | - for(i = 0; i < sg_count; i++) { |
|---|
| 1771 | | - int sg_size; |
|---|
| 1772 | | - |
|---|
| 1773 | | - if (!(sg[i].flag_count & 0x10000000 /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT*/)) { |
|---|
| 1774 | | - printk(KERN_DEBUG"%s:Bad SG element %d - not simple (%x)\n",pHba->name,i, sg[i].flag_count); |
|---|
| 1775 | | - rcode = -EINVAL; |
|---|
| 1776 | | - goto cleanup; |
|---|
| 1777 | | - } |
|---|
| 1778 | | - sg_size = sg[i].flag_count & 0xffffff; |
|---|
| 1779 | | - /* Allocate memory for the transfer */ |
|---|
| 1780 | | - p = dma_alloc_coherent(&pHba->pDev->dev, sg_size, &addr, GFP_KERNEL); |
|---|
| 1781 | | - if(!p) { |
|---|
| 1782 | | - printk(KERN_DEBUG"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", |
|---|
| 1783 | | - pHba->name,sg_size,i,sg_count); |
|---|
| 1784 | | - rcode = -ENOMEM; |
|---|
| 1785 | | - goto cleanup; |
|---|
| 1786 | | - } |
|---|
| 1787 | | - sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame. |
|---|
| 1788 | | - /* Copy in the user's SG buffer if necessary */ |
|---|
| 1789 | | - if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) { |
|---|
| 1790 | | - // sg_simple_element API is 32 bit |
|---|
| 1791 | | - if (copy_from_user(p,(void __user *)(ulong)sg[i].addr_bus, sg_size)) { |
|---|
| 1792 | | - printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",pHba->name,i); |
|---|
| 1793 | | - rcode = -EFAULT; |
|---|
| 1794 | | - goto cleanup; |
|---|
| 1795 | | - } |
|---|
| 1796 | | - } |
|---|
| 1797 | | - /* sg_simple_element API is 32 bit, but addr < 4GB */ |
|---|
| 1798 | | - sg[i].addr_bus = addr; |
|---|
| 1799 | | - } |
|---|
| 1800 | | - } |
|---|
| 1801 | | - |
|---|
| 1802 | | - do { |
|---|
| 1803 | | - /* |
|---|
| 1804 | | - * Stop any new commands from enterring the |
|---|
| 1805 | | - * controller while processing the ioctl |
|---|
| 1806 | | - */ |
|---|
| 1807 | | - if (pHba->host) { |
|---|
| 1808 | | - scsi_block_requests(pHba->host); |
|---|
| 1809 | | - spin_lock_irqsave(pHba->host->host_lock, flags); |
|---|
| 1810 | | - } |
|---|
| 1811 | | - rcode = adpt_i2o_post_wait(pHba, msg, size, FOREVER); |
|---|
| 1812 | | - if (rcode != 0) |
|---|
| 1813 | | - printk("adpt_i2o_passthru: post wait failed %d %p\n", |
|---|
| 1814 | | - rcode, reply); |
|---|
| 1815 | | - if (pHba->host) { |
|---|
| 1816 | | - spin_unlock_irqrestore(pHba->host->host_lock, flags); |
|---|
| 1817 | | - scsi_unblock_requests(pHba->host); |
|---|
| 1818 | | - } |
|---|
| 1819 | | - } while (rcode == -ETIMEDOUT); |
|---|
| 1820 | | - |
|---|
| 1821 | | - if(rcode){ |
|---|
| 1822 | | - goto cleanup; |
|---|
| 1823 | | - } |
|---|
| 1824 | | - |
|---|
| 1825 | | - if(sg_offset) { |
|---|
| 1826 | | - /* Copy back the Scatter Gather buffers back to user space */ |
|---|
| 1827 | | - u32 j; |
|---|
| 1828 | | - // TODO add 64 bit API |
|---|
| 1829 | | - struct sg_simple_element* sg; |
|---|
| 1830 | | - int sg_size; |
|---|
| 1831 | | - |
|---|
| 1832 | | - // re-acquire the original message to handle correctly the sg copy operation |
|---|
| 1833 | | - memset(&msg, 0, MAX_MESSAGE_SIZE*4); |
|---|
| 1834 | | - // get user msg size in u32s |
|---|
| 1835 | | - if(get_user(size, &user_msg[0])){ |
|---|
| 1836 | | - rcode = -EFAULT; |
|---|
| 1837 | | - goto cleanup; |
|---|
| 1838 | | - } |
|---|
| 1839 | | - size = size>>16; |
|---|
| 1840 | | - size *= 4; |
|---|
| 1841 | | - if (size > MAX_MESSAGE_SIZE) { |
|---|
| 1842 | | - rcode = -EINVAL; |
|---|
| 1843 | | - goto cleanup; |
|---|
| 1844 | | - } |
|---|
| 1845 | | - /* Copy in the user's I2O command */ |
|---|
| 1846 | | - if (copy_from_user (msg, user_msg, size)) { |
|---|
| 1847 | | - rcode = -EFAULT; |
|---|
| 1848 | | - goto cleanup; |
|---|
| 1849 | | - } |
|---|
| 1850 | | - sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element); |
|---|
| 1851 | | - |
|---|
| 1852 | | - // TODO add 64 bit API |
|---|
| 1853 | | - sg = (struct sg_simple_element*)(msg + sg_offset); |
|---|
| 1854 | | - for (j = 0; j < sg_count; j++) { |
|---|
| 1855 | | - /* Copy out the SG list to user's buffer if necessary */ |
|---|
| 1856 | | - if(! (sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) { |
|---|
| 1857 | | - sg_size = sg[j].flag_count & 0xffffff; |
|---|
| 1858 | | - // sg_simple_element API is 32 bit |
|---|
| 1859 | | - if (copy_to_user((void __user *)(ulong)sg[j].addr_bus,sg_list[j], sg_size)) { |
|---|
| 1860 | | - printk(KERN_WARNING"%s: Could not copy %p TO user %x\n",pHba->name, sg_list[j], sg[j].addr_bus); |
|---|
| 1861 | | - rcode = -EFAULT; |
|---|
| 1862 | | - goto cleanup; |
|---|
| 1863 | | - } |
|---|
| 1864 | | - } |
|---|
| 1865 | | - } |
|---|
| 1866 | | - } |
|---|
| 1867 | | - |
|---|
| 1868 | | - /* Copy back the reply to user space */ |
|---|
| 1869 | | - if (reply_size) { |
|---|
| 1870 | | - // we wrote our own values for context - now restore the user supplied ones |
|---|
| 1871 | | - if(copy_from_user(reply+2, user_msg+2, sizeof(u32)*2)) { |
|---|
| 1872 | | - printk(KERN_WARNING"%s: Could not copy message context FROM user\n",pHba->name); |
|---|
| 1873 | | - rcode = -EFAULT; |
|---|
| 1874 | | - } |
|---|
| 1875 | | - if(copy_to_user(user_reply, reply, reply_size)) { |
|---|
| 1876 | | - printk(KERN_WARNING"%s: Could not copy reply TO user\n",pHba->name); |
|---|
| 1877 | | - rcode = -EFAULT; |
|---|
| 1878 | | - } |
|---|
| 1879 | | - } |
|---|
| 1880 | | - |
|---|
| 1881 | | - |
|---|
| 1882 | | -cleanup: |
|---|
| 1883 | | - if (rcode != -ETIME && rcode != -EINTR) { |
|---|
| 1884 | | - struct sg_simple_element *sg = |
|---|
| 1885 | | - (struct sg_simple_element*) (msg +sg_offset); |
|---|
| 1886 | | - while(sg_index) { |
|---|
| 1887 | | - if(sg_list[--sg_index]) { |
|---|
| 1888 | | - dma_free_coherent(&pHba->pDev->dev, |
|---|
| 1889 | | - sg[sg_index].flag_count & 0xffffff, |
|---|
| 1890 | | - sg_list[sg_index], |
|---|
| 1891 | | - sg[sg_index].addr_bus); |
|---|
| 1892 | | - } |
|---|
| 1893 | | - } |
|---|
| 1894 | | - } |
|---|
| 1895 | | - |
|---|
| 1896 | | -free: |
|---|
| 1897 | | - kfree(sg_list); |
|---|
| 1898 | | - kfree(reply); |
|---|
| 1899 | | - return rcode; |
|---|
| 1900 | | -} |
|---|
| 1901 | | - |
|---|
| 1902 | 1606 | #if defined __ia64__ |
|---|
| 1903 | 1607 | static void adpt_ia64_info(sysInfo_S* si) |
|---|
| 1904 | 1608 | { |
|---|
| .. | .. |
|---|
| 2025 | 1729 | return -EFAULT; |
|---|
| 2026 | 1730 | } |
|---|
| 2027 | 1731 | break; |
|---|
| 2028 | | - case I2OUSRCMD: |
|---|
| 2029 | | - return adpt_i2o_passthru(pHba, argp); |
|---|
| 2030 | 1732 | |
|---|
| 2031 | 1733 | case DPT_CTRLINFO:{ |
|---|
| 2032 | 1734 | drvrHBAinfo_S HbaInfo; |
|---|
| .. | .. |
|---|
| 2163 | 1865 | } else { |
|---|
| 2164 | 1866 | /* Ick, we should *never* be here */ |
|---|
| 2165 | 1867 | printk(KERN_ERR "dpti: reply frame not from pool\n"); |
|---|
| 2166 | | - reply = (u8 *)bus_to_virt(m); |
|---|
| 1868 | + continue; |
|---|
| 2167 | 1869 | } |
|---|
| 2168 | 1870 | |
|---|
| 2169 | 1871 | if (readl(reply) & MSG_FAIL) { |
|---|
| .. | .. |
|---|
| 2183 | 1885 | adpt_send_nop(pHba, old_m); |
|---|
| 2184 | 1886 | } |
|---|
| 2185 | 1887 | context = readl(reply+8); |
|---|
| 2186 | | - if(context & 0x40000000){ // IOCTL |
|---|
| 2187 | | - void *p = adpt_ioctl_from_context(pHba, readl(reply+12)); |
|---|
| 2188 | | - if( p != NULL) { |
|---|
| 2189 | | - memcpy_fromio(p, reply, REPLY_FRAME_SIZE * 4); |
|---|
| 2190 | | - } |
|---|
| 2191 | | - // All IOCTLs will also be post wait |
|---|
| 2192 | | - } |
|---|
| 2193 | 1888 | if(context & 0x80000000){ // Post wait message |
|---|
| 2194 | 1889 | status = readl(reply+16); |
|---|
| 2195 | 1890 | if(status >> 24){ |
|---|
| .. | .. |
|---|
| 2197 | 1892 | } else { |
|---|
| 2198 | 1893 | status = I2O_POST_WAIT_OK; |
|---|
| 2199 | 1894 | } |
|---|
| 2200 | | - if(!(context & 0x40000000)) { |
|---|
| 2201 | | - cmd = adpt_cmd_from_context(pHba, |
|---|
| 2202 | | - readl(reply+12)); |
|---|
| 2203 | | - if(cmd != NULL) { |
|---|
| 2204 | | - printk(KERN_WARNING"%s: Apparent SCSI cmd in Post Wait Context - cmd=%p context=%x\n", pHba->name, cmd, context); |
|---|
| 2205 | | - } |
|---|
| 1895 | + /* |
|---|
| 1896 | + * The request tag is one less than the command tag |
|---|
| 1897 | + * as the firmware might treat a 0 tag as invalid |
|---|
| 1898 | + */ |
|---|
| 1899 | + cmd = scsi_host_find_tag(pHba->host, |
|---|
| 1900 | + readl(reply + 12) - 1); |
|---|
| 1901 | + if(cmd != NULL) { |
|---|
| 1902 | + printk(KERN_WARNING"%s: Apparent SCSI cmd in Post Wait Context - cmd=%p context=%x\n", pHba->name, cmd, context); |
|---|
| 2206 | 1903 | } |
|---|
| 2207 | 1904 | adpt_i2o_post_wait_complete(context, status); |
|---|
| 2208 | 1905 | } else { // SCSI message |
|---|
| 2209 | | - cmd = adpt_cmd_from_context (pHba, readl(reply+12)); |
|---|
| 1906 | + /* |
|---|
| 1907 | + * The request tag is one less than the command tag |
|---|
| 1908 | + * as the firmware might treat a 0 tag as invalid |
|---|
| 1909 | + */ |
|---|
| 1910 | + cmd = scsi_host_find_tag(pHba->host, |
|---|
| 1911 | + readl(reply + 12) - 1); |
|---|
| 2210 | 1912 | if(cmd != NULL){ |
|---|
| 2211 | 1913 | scsi_dma_unmap(cmd); |
|---|
| 2212 | | - if(cmd->serial_number != 0) { // If not timedout |
|---|
| 2213 | | - adpt_i2o_to_scsi(reply, cmd); |
|---|
| 2214 | | - } |
|---|
| 1914 | + adpt_i2o_scsi_complete(reply, cmd); |
|---|
| 2215 | 1915 | } |
|---|
| 2216 | 1916 | } |
|---|
| 2217 | 1917 | writel(m, pHba->reply_port); |
|---|
| .. | .. |
|---|
| 2277 | 1977 | // I2O_CMD_SCSI_EXEC |
|---|
| 2278 | 1978 | msg[1] = ((0xff<<24)|(HOST_TID<<12)|d->tid); |
|---|
| 2279 | 1979 | msg[2] = 0; |
|---|
| 2280 | | - msg[3] = adpt_cmd_to_context(cmd); /* Want SCSI control block back */ |
|---|
| 1980 | + /* Add 1 to avoid firmware treating it as invalid command */ |
|---|
| 1981 | + msg[3] = cmd->request->tag + 1; |
|---|
| 2281 | 1982 | // Our cards use the transaction context as the tag for queueing |
|---|
| 2282 | 1983 | // Adaptec/DPT Private stuff |
|---|
| 2283 | 1984 | msg[4] = I2O_CMD_SCSI_EXEC|(DPT_ORGANIZATION_ID<<16); |
|---|
| .. | .. |
|---|
| 2372 | 2073 | host->unique_id = (u32)sys_tbl_pa + pHba->unit; |
|---|
| 2373 | 2074 | host->sg_tablesize = pHba->sg_tablesize; |
|---|
| 2374 | 2075 | host->can_queue = pHba->post_fifo_size; |
|---|
| 2375 | | - host->use_cmd_list = 1; |
|---|
| 2376 | 2076 | |
|---|
| 2377 | 2077 | return 0; |
|---|
| 2378 | 2078 | } |
|---|
| 2379 | 2079 | |
|---|
| 2380 | 2080 | |
|---|
| 2381 | | -static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd) |
|---|
| 2081 | +static void adpt_i2o_scsi_complete(void __iomem *reply, struct scsi_cmnd *cmd) |
|---|
| 2382 | 2082 | { |
|---|
| 2383 | 2083 | adpt_hba* pHba; |
|---|
| 2384 | 2084 | u32 hba_status; |
|---|
| .. | .. |
|---|
| 2496 | 2196 | if(cmd->scsi_done != NULL){ |
|---|
| 2497 | 2197 | cmd->scsi_done(cmd); |
|---|
| 2498 | 2198 | } |
|---|
| 2499 | | - return cmd->result; |
|---|
| 2500 | 2199 | } |
|---|
| 2501 | 2200 | |
|---|
| 2502 | 2201 | |
|---|
| .. | .. |
|---|
| 2684 | 2383 | return 0; |
|---|
| 2685 | 2384 | } |
|---|
| 2686 | 2385 | |
|---|
| 2687 | | -static void adpt_fail_posted_scbs(adpt_hba* pHba) |
|---|
| 2688 | | -{ |
|---|
| 2689 | | - struct scsi_cmnd* cmd = NULL; |
|---|
| 2690 | | - struct scsi_device* d = NULL; |
|---|
| 2691 | | - |
|---|
| 2692 | | - shost_for_each_device(d, pHba->host) { |
|---|
| 2693 | | - unsigned long flags; |
|---|
| 2694 | | - spin_lock_irqsave(&d->list_lock, flags); |
|---|
| 2695 | | - list_for_each_entry(cmd, &d->cmd_list, list) { |
|---|
| 2696 | | - if(cmd->serial_number == 0){ |
|---|
| 2697 | | - continue; |
|---|
| 2698 | | - } |
|---|
| 2699 | | - cmd->result = (DID_OK << 16) | (QUEUE_FULL <<1); |
|---|
| 2700 | | - cmd->scsi_done(cmd); |
|---|
| 2701 | | - } |
|---|
| 2702 | | - spin_unlock_irqrestore(&d->list_lock, flags); |
|---|
| 2703 | | - } |
|---|
| 2704 | | -} |
|---|
| 2705 | | - |
|---|
| 2706 | | - |
|---|
| 2707 | 2386 | /*============================================================================ |
|---|
| 2708 | 2387 | * Routines from i2o subsystem |
|---|
| 2709 | 2388 | *============================================================================ |
|---|
| .. | .. |
|---|
| 2843 | 2522 | pHba->name); |
|---|
| 2844 | 2523 | return -ENOMEM; |
|---|
| 2845 | 2524 | } |
|---|
| 2846 | | - memset(status, 0, 4); |
|---|
| 2847 | 2525 | |
|---|
| 2848 | 2526 | writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]); |
|---|
| 2849 | 2527 | writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]); |
|---|
| .. | .. |
|---|
| 2897 | 2575 | printk(KERN_ERR "%s: Could not allocate reply pool\n", pHba->name); |
|---|
| 2898 | 2576 | return -ENOMEM; |
|---|
| 2899 | 2577 | } |
|---|
| 2900 | | - memset(pHba->reply_pool, 0 , pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4); |
|---|
| 2901 | 2578 | |
|---|
| 2902 | 2579 | for(i = 0; i < pHba->reply_fifo_size; i++) { |
|---|
| 2903 | 2580 | writel(pHba->reply_pool_pa + (i * REPLY_FRAME_SIZE * 4), |
|---|
| .. | .. |
|---|
| 3132 | 2809 | printk(KERN_WARNING "SysTab Set failed. Out of memory.\n"); |
|---|
| 3133 | 2810 | return -ENOMEM; |
|---|
| 3134 | 2811 | } |
|---|
| 3135 | | - memset(sys_tbl, 0, sys_tbl_len); |
|---|
| 3136 | 2812 | |
|---|
| 3137 | 2813 | sys_tbl->num_entries = hba_count; |
|---|
| 3138 | 2814 | sys_tbl->version = I2OVERSION; |
|---|
| .. | .. |
|---|
| 3427 | 3103 | return -((res[1] >> 16) & 0xFF); /* -BlockStatus */ |
|---|
| 3428 | 3104 | } |
|---|
| 3429 | 3105 | |
|---|
| 3430 | | - return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ |
|---|
| 3106 | + return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ |
|---|
| 3431 | 3107 | } |
|---|
| 3432 | 3108 | |
|---|
| 3433 | 3109 | |
|---|
| .. | .. |
|---|
| 3500 | 3176 | |
|---|
| 3501 | 3177 | static int adpt_i2o_systab_send(adpt_hba* pHba) |
|---|
| 3502 | 3178 | { |
|---|
| 3503 | | - u32 msg[12]; |
|---|
| 3504 | | - int ret; |
|---|
| 3179 | + u32 msg[12]; |
|---|
| 3180 | + int ret; |
|---|
| 3505 | 3181 | |
|---|
| 3506 | 3182 | msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6; |
|---|
| 3507 | 3183 | msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; |
|---|
| .. | .. |
|---|
| 3569 | 3245 | .slave_configure = adpt_slave_configure, |
|---|
| 3570 | 3246 | .can_queue = MAX_TO_IOP_MESSAGES, |
|---|
| 3571 | 3247 | .this_id = 7, |
|---|
| 3572 | | - .use_clustering = ENABLE_CLUSTERING, |
|---|
| 3573 | 3248 | }; |
|---|
| 3574 | 3249 | |
|---|
| 3575 | 3250 | static int __init adpt_init(void) |
|---|