| .. | .. |
|---|
| 56 | 56 | #include <linux/mutex.h> |
|---|
| 57 | 57 | |
|---|
| 58 | 58 | #include <asm/processor.h> /* for boot_cpu_data */ |
|---|
| 59 | | -#include <asm/io.h> /* for virt_to_bus, etc. */ |
|---|
| 59 | +#include <asm/io.h> |
|---|
| 60 | 60 | |
|---|
| 61 | 61 | #include <scsi/scsi.h> |
|---|
| 62 | 62 | #include <scsi/scsi_cmnd.h> |
|---|
| .. | .. |
|---|
| 580 | 580 | } |
|---|
| 581 | 581 | } |
|---|
| 582 | 582 | return 0; |
|---|
| 583 | | -} |
|---|
| 584 | | - |
|---|
| 585 | | -/* |
|---|
| 586 | | - * Turn a pointer to ioctl reply data into an u32 'context' |
|---|
| 587 | | - */ |
|---|
| 588 | | -static u32 adpt_ioctl_to_context(adpt_hba * pHba, void *reply) |
|---|
| 589 | | -{ |
|---|
| 590 | | -#if BITS_PER_LONG == 32 |
|---|
| 591 | | - return (u32)(unsigned long)reply; |
|---|
| 592 | | -#else |
|---|
| 593 | | - ulong flags = 0; |
|---|
| 594 | | - u32 nr, i; |
|---|
| 595 | | - |
|---|
| 596 | | - spin_lock_irqsave(pHba->host->host_lock, flags); |
|---|
| 597 | | - nr = ARRAY_SIZE(pHba->ioctl_reply_context); |
|---|
| 598 | | - for (i = 0; i < nr; i++) { |
|---|
| 599 | | - if (pHba->ioctl_reply_context[i] == NULL) { |
|---|
| 600 | | - pHba->ioctl_reply_context[i] = reply; |
|---|
| 601 | | - break; |
|---|
| 602 | | - } |
|---|
| 603 | | - } |
|---|
| 604 | | - spin_unlock_irqrestore(pHba->host->host_lock, flags); |
|---|
| 605 | | - if (i >= nr) { |
|---|
| 606 | | - printk(KERN_WARNING"%s: Too many outstanding " |
|---|
| 607 | | - "ioctl commands\n", pHba->name); |
|---|
| 608 | | - return (u32)-1; |
|---|
| 609 | | - } |
|---|
| 610 | | - |
|---|
| 611 | | - return i; |
|---|
| 612 | | -#endif |
|---|
| 613 | | -} |
|---|
| 614 | | - |
|---|
| 615 | | -/* |
|---|
| 616 | | - * Go from an u32 'context' to a pointer to ioctl reply data. |
|---|
| 617 | | - */ |
|---|
| 618 | | -static void *adpt_ioctl_from_context(adpt_hba *pHba, u32 context) |
|---|
| 619 | | -{ |
|---|
| 620 | | -#if BITS_PER_LONG == 32 |
|---|
| 621 | | - return (void *)(unsigned long)context; |
|---|
| 622 | | -#else |
|---|
| 623 | | - void *p = pHba->ioctl_reply_context[context]; |
|---|
| 624 | | - pHba->ioctl_reply_context[context] = NULL; |
|---|
| 625 | | - |
|---|
| 626 | | - return p; |
|---|
| 627 | | -#endif |
|---|
| 628 | 583 | } |
|---|
| 629 | 584 | |
|---|
| 630 | 585 | /*=========================================================================== |
|---|
| .. | .. |
|---|
| 1648 | 1603 | return 0; |
|---|
| 1649 | 1604 | } |
|---|
| 1650 | 1605 | |
|---|
| 1651 | | - |
|---|
| 1652 | | -static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg) |
|---|
| 1653 | | -{ |
|---|
| 1654 | | - u32 msg[MAX_MESSAGE_SIZE]; |
|---|
| 1655 | | - u32* reply = NULL; |
|---|
| 1656 | | - u32 size = 0; |
|---|
| 1657 | | - u32 reply_size = 0; |
|---|
| 1658 | | - u32 __user *user_msg = arg; |
|---|
| 1659 | | - u32 __user * user_reply = NULL; |
|---|
| 1660 | | - void **sg_list = NULL; |
|---|
| 1661 | | - u32 sg_offset = 0; |
|---|
| 1662 | | - u32 sg_count = 0; |
|---|
| 1663 | | - int sg_index = 0; |
|---|
| 1664 | | - u32 i = 0; |
|---|
| 1665 | | - u32 rcode = 0; |
|---|
| 1666 | | - void *p = NULL; |
|---|
| 1667 | | - dma_addr_t addr; |
|---|
| 1668 | | - ulong flags = 0; |
|---|
| 1669 | | - |
|---|
| 1670 | | - memset(&msg, 0, MAX_MESSAGE_SIZE*4); |
|---|
| 1671 | | - // get user msg size in u32s |
|---|
| 1672 | | - if(get_user(size, &user_msg[0])){ |
|---|
| 1673 | | - return -EFAULT; |
|---|
| 1674 | | - } |
|---|
| 1675 | | - size = size>>16; |
|---|
| 1676 | | - |
|---|
| 1677 | | - user_reply = &user_msg[size]; |
|---|
| 1678 | | - if(size > MAX_MESSAGE_SIZE){ |
|---|
| 1679 | | - return -EFAULT; |
|---|
| 1680 | | - } |
|---|
| 1681 | | - size *= 4; // Convert to bytes |
|---|
| 1682 | | - |
|---|
| 1683 | | - /* Copy in the user's I2O command */ |
|---|
| 1684 | | - if(copy_from_user(msg, user_msg, size)) { |
|---|
| 1685 | | - return -EFAULT; |
|---|
| 1686 | | - } |
|---|
| 1687 | | - get_user(reply_size, &user_reply[0]); |
|---|
| 1688 | | - reply_size = reply_size>>16; |
|---|
| 1689 | | - if(reply_size > REPLY_FRAME_SIZE){ |
|---|
| 1690 | | - reply_size = REPLY_FRAME_SIZE; |
|---|
| 1691 | | - } |
|---|
| 1692 | | - reply_size *= 4; |
|---|
| 1693 | | - reply = kzalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL); |
|---|
| 1694 | | - if(reply == NULL) { |
|---|
| 1695 | | - printk(KERN_WARNING"%s: Could not allocate reply buffer\n",pHba->name); |
|---|
| 1696 | | - return -ENOMEM; |
|---|
| 1697 | | - } |
|---|
| 1698 | | - sg_offset = (msg[0]>>4)&0xf; |
|---|
| 1699 | | - msg[2] = 0x40000000; // IOCTL context |
|---|
| 1700 | | - msg[3] = adpt_ioctl_to_context(pHba, reply); |
|---|
| 1701 | | - if (msg[3] == (u32)-1) { |
|---|
| 1702 | | - rcode = -EBUSY; |
|---|
| 1703 | | - goto free; |
|---|
| 1704 | | - } |
|---|
| 1705 | | - |
|---|
| 1706 | | - sg_list = kcalloc(pHba->sg_tablesize, sizeof(*sg_list), GFP_KERNEL); |
|---|
| 1707 | | - if (!sg_list) { |
|---|
| 1708 | | - rcode = -ENOMEM; |
|---|
| 1709 | | - goto free; |
|---|
| 1710 | | - } |
|---|
| 1711 | | - if(sg_offset) { |
|---|
| 1712 | | - // TODO add 64 bit API |
|---|
| 1713 | | - struct sg_simple_element *sg = (struct sg_simple_element*) (msg+sg_offset); |
|---|
| 1714 | | - sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element); |
|---|
| 1715 | | - if (sg_count > pHba->sg_tablesize){ |
|---|
| 1716 | | - printk(KERN_DEBUG"%s:IOCTL SG List too large (%u)\n", pHba->name,sg_count); |
|---|
| 1717 | | - rcode = -EINVAL; |
|---|
| 1718 | | - goto free; |
|---|
| 1719 | | - } |
|---|
| 1720 | | - |
|---|
| 1721 | | - for(i = 0; i < sg_count; i++) { |
|---|
| 1722 | | - int sg_size; |
|---|
| 1723 | | - |
|---|
| 1724 | | - if (!(sg[i].flag_count & 0x10000000 /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT*/)) { |
|---|
| 1725 | | - printk(KERN_DEBUG"%s:Bad SG element %d - not simple (%x)\n",pHba->name,i, sg[i].flag_count); |
|---|
| 1726 | | - rcode = -EINVAL; |
|---|
| 1727 | | - goto cleanup; |
|---|
| 1728 | | - } |
|---|
| 1729 | | - sg_size = sg[i].flag_count & 0xffffff; |
|---|
| 1730 | | - /* Allocate memory for the transfer */ |
|---|
| 1731 | | - p = dma_alloc_coherent(&pHba->pDev->dev, sg_size, &addr, GFP_KERNEL); |
|---|
| 1732 | | - if(!p) { |
|---|
| 1733 | | - printk(KERN_DEBUG"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", |
|---|
| 1734 | | - pHba->name,sg_size,i,sg_count); |
|---|
| 1735 | | - rcode = -ENOMEM; |
|---|
| 1736 | | - goto cleanup; |
|---|
| 1737 | | - } |
|---|
| 1738 | | - sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame. |
|---|
| 1739 | | - /* Copy in the user's SG buffer if necessary */ |
|---|
| 1740 | | - if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) { |
|---|
| 1741 | | - // sg_simple_element API is 32 bit |
|---|
| 1742 | | - if (copy_from_user(p,(void __user *)(ulong)sg[i].addr_bus, sg_size)) { |
|---|
| 1743 | | - printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",pHba->name,i); |
|---|
| 1744 | | - rcode = -EFAULT; |
|---|
| 1745 | | - goto cleanup; |
|---|
| 1746 | | - } |
|---|
| 1747 | | - } |
|---|
| 1748 | | - /* sg_simple_element API is 32 bit, but addr < 4GB */ |
|---|
| 1749 | | - sg[i].addr_bus = addr; |
|---|
| 1750 | | - } |
|---|
| 1751 | | - } |
|---|
| 1752 | | - |
|---|
| 1753 | | - do { |
|---|
| 1754 | | - /* |
|---|
| 1755 | | - * Stop any new commands from enterring the |
|---|
| 1756 | | - * controller while processing the ioctl |
|---|
| 1757 | | - */ |
|---|
| 1758 | | - if (pHba->host) { |
|---|
| 1759 | | - scsi_block_requests(pHba->host); |
|---|
| 1760 | | - spin_lock_irqsave(pHba->host->host_lock, flags); |
|---|
| 1761 | | - } |
|---|
| 1762 | | - rcode = adpt_i2o_post_wait(pHba, msg, size, FOREVER); |
|---|
| 1763 | | - if (rcode != 0) |
|---|
| 1764 | | - printk("adpt_i2o_passthru: post wait failed %d %p\n", |
|---|
| 1765 | | - rcode, reply); |
|---|
| 1766 | | - if (pHba->host) { |
|---|
| 1767 | | - spin_unlock_irqrestore(pHba->host->host_lock, flags); |
|---|
| 1768 | | - scsi_unblock_requests(pHba->host); |
|---|
| 1769 | | - } |
|---|
| 1770 | | - } while (rcode == -ETIMEDOUT); |
|---|
| 1771 | | - |
|---|
| 1772 | | - if(rcode){ |
|---|
| 1773 | | - goto cleanup; |
|---|
| 1774 | | - } |
|---|
| 1775 | | - |
|---|
| 1776 | | - if(sg_offset) { |
|---|
| 1777 | | - /* Copy back the Scatter Gather buffers back to user space */ |
|---|
| 1778 | | - u32 j; |
|---|
| 1779 | | - // TODO add 64 bit API |
|---|
| 1780 | | - struct sg_simple_element* sg; |
|---|
| 1781 | | - int sg_size; |
|---|
| 1782 | | - |
|---|
| 1783 | | - // re-acquire the original message to handle correctly the sg copy operation |
|---|
| 1784 | | - memset(&msg, 0, MAX_MESSAGE_SIZE*4); |
|---|
| 1785 | | - // get user msg size in u32s |
|---|
| 1786 | | - if(get_user(size, &user_msg[0])){ |
|---|
| 1787 | | - rcode = -EFAULT; |
|---|
| 1788 | | - goto cleanup; |
|---|
| 1789 | | - } |
|---|
| 1790 | | - size = size>>16; |
|---|
| 1791 | | - size *= 4; |
|---|
| 1792 | | - if (size > MAX_MESSAGE_SIZE) { |
|---|
| 1793 | | - rcode = -EINVAL; |
|---|
| 1794 | | - goto cleanup; |
|---|
| 1795 | | - } |
|---|
| 1796 | | - /* Copy in the user's I2O command */ |
|---|
| 1797 | | - if (copy_from_user (msg, user_msg, size)) { |
|---|
| 1798 | | - rcode = -EFAULT; |
|---|
| 1799 | | - goto cleanup; |
|---|
| 1800 | | - } |
|---|
| 1801 | | - sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element); |
|---|
| 1802 | | - |
|---|
| 1803 | | - // TODO add 64 bit API |
|---|
| 1804 | | - sg = (struct sg_simple_element*)(msg + sg_offset); |
|---|
| 1805 | | - for (j = 0; j < sg_count; j++) { |
|---|
| 1806 | | - /* Copy out the SG list to user's buffer if necessary */ |
|---|
| 1807 | | - if(! (sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) { |
|---|
| 1808 | | - sg_size = sg[j].flag_count & 0xffffff; |
|---|
| 1809 | | - // sg_simple_element API is 32 bit |
|---|
| 1810 | | - if (copy_to_user((void __user *)(ulong)sg[j].addr_bus,sg_list[j], sg_size)) { |
|---|
| 1811 | | - printk(KERN_WARNING"%s: Could not copy %p TO user %x\n",pHba->name, sg_list[j], sg[j].addr_bus); |
|---|
| 1812 | | - rcode = -EFAULT; |
|---|
| 1813 | | - goto cleanup; |
|---|
| 1814 | | - } |
|---|
| 1815 | | - } |
|---|
| 1816 | | - } |
|---|
| 1817 | | - } |
|---|
| 1818 | | - |
|---|
| 1819 | | - /* Copy back the reply to user space */ |
|---|
| 1820 | | - if (reply_size) { |
|---|
| 1821 | | - // we wrote our own values for context - now restore the user supplied ones |
|---|
| 1822 | | - if(copy_from_user(reply+2, user_msg+2, sizeof(u32)*2)) { |
|---|
| 1823 | | - printk(KERN_WARNING"%s: Could not copy message context FROM user\n",pHba->name); |
|---|
| 1824 | | - rcode = -EFAULT; |
|---|
| 1825 | | - } |
|---|
| 1826 | | - if(copy_to_user(user_reply, reply, reply_size)) { |
|---|
| 1827 | | - printk(KERN_WARNING"%s: Could not copy reply TO user\n",pHba->name); |
|---|
| 1828 | | - rcode = -EFAULT; |
|---|
| 1829 | | - } |
|---|
| 1830 | | - } |
|---|
| 1831 | | - |
|---|
| 1832 | | - |
|---|
| 1833 | | -cleanup: |
|---|
| 1834 | | - if (rcode != -ETIME && rcode != -EINTR) { |
|---|
| 1835 | | - struct sg_simple_element *sg = |
|---|
| 1836 | | - (struct sg_simple_element*) (msg +sg_offset); |
|---|
| 1837 | | - while(sg_index) { |
|---|
| 1838 | | - if(sg_list[--sg_index]) { |
|---|
| 1839 | | - dma_free_coherent(&pHba->pDev->dev, |
|---|
| 1840 | | - sg[sg_index].flag_count & 0xffffff, |
|---|
| 1841 | | - sg_list[sg_index], |
|---|
| 1842 | | - sg[sg_index].addr_bus); |
|---|
| 1843 | | - } |
|---|
| 1844 | | - } |
|---|
| 1845 | | - } |
|---|
| 1846 | | - |
|---|
| 1847 | | -free: |
|---|
| 1848 | | - kfree(sg_list); |
|---|
| 1849 | | - kfree(reply); |
|---|
| 1850 | | - return rcode; |
|---|
| 1851 | | -} |
|---|
| 1852 | | - |
|---|
| 1853 | 1606 | #if defined __ia64__ |
|---|
| 1854 | 1607 | static void adpt_ia64_info(sysInfo_S* si) |
|---|
| 1855 | 1608 | { |
|---|
| .. | .. |
|---|
| 1976 | 1729 | return -EFAULT; |
|---|
| 1977 | 1730 | } |
|---|
| 1978 | 1731 | break; |
|---|
| 1979 | | - case I2OUSRCMD: |
|---|
| 1980 | | - return adpt_i2o_passthru(pHba, argp); |
|---|
| 1981 | 1732 | |
|---|
| 1982 | 1733 | case DPT_CTRLINFO:{ |
|---|
| 1983 | 1734 | drvrHBAinfo_S HbaInfo; |
|---|
| .. | .. |
|---|
| 2114 | 1865 | } else { |
|---|
| 2115 | 1866 | /* Ick, we should *never* be here */ |
|---|
| 2116 | 1867 | printk(KERN_ERR "dpti: reply frame not from pool\n"); |
|---|
| 2117 | | - reply = (u8 *)bus_to_virt(m); |
|---|
| 1868 | + continue; |
|---|
| 2118 | 1869 | } |
|---|
| 2119 | 1870 | |
|---|
| 2120 | 1871 | if (readl(reply) & MSG_FAIL) { |
|---|
| .. | .. |
|---|
| 2134 | 1885 | adpt_send_nop(pHba, old_m); |
|---|
| 2135 | 1886 | } |
|---|
| 2136 | 1887 | context = readl(reply+8); |
|---|
| 2137 | | - if(context & 0x40000000){ // IOCTL |
|---|
| 2138 | | - void *p = adpt_ioctl_from_context(pHba, readl(reply+12)); |
|---|
| 2139 | | - if( p != NULL) { |
|---|
| 2140 | | - memcpy_fromio(p, reply, REPLY_FRAME_SIZE * 4); |
|---|
| 2141 | | - } |
|---|
| 2142 | | - // All IOCTLs will also be post wait |
|---|
| 2143 | | - } |
|---|
| 2144 | 1888 | if(context & 0x80000000){ // Post wait message |
|---|
| 2145 | 1889 | status = readl(reply+16); |
|---|
| 2146 | 1890 | if(status >> 24){ |
|---|
| .. | .. |
|---|
| 2148 | 1892 | } else { |
|---|
| 2149 | 1893 | status = I2O_POST_WAIT_OK; |
|---|
| 2150 | 1894 | } |
|---|
| 2151 | | - if(!(context & 0x40000000)) { |
|---|
| 2152 | | - /* |
|---|
| 2153 | | - * The request tag is one less than the command tag |
|---|
| 2154 | | - * as the firmware might treat a 0 tag as invalid |
|---|
| 2155 | | - */ |
|---|
| 2156 | | - cmd = scsi_host_find_tag(pHba->host, |
|---|
| 2157 | | - readl(reply + 12) - 1); |
|---|
| 2158 | | - if(cmd != NULL) { |
|---|
| 2159 | | - printk(KERN_WARNING"%s: Apparent SCSI cmd in Post Wait Context - cmd=%p context=%x\n", pHba->name, cmd, context); |
|---|
| 2160 | | - } |
|---|
| 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); |
|---|
| 2161 | 1903 | } |
|---|
| 2162 | 1904 | adpt_i2o_post_wait_complete(context, status); |
|---|
| 2163 | 1905 | } else { // SCSI message |
|---|