diff options
| author | Stephen M. Cameron <scameron@beardog.cce.hp.com> | 2010-08-26 14:56:30 -0400 |
|---|---|---|
| committer | Jens Axboe <jaxboe@fusionio.com> | 2010-09-10 06:12:39 -0400 |
| commit | 0c9f5ba7cb7435ea4b99599de4af0729f0740647 (patch) | |
| tree | 1c80511d7a57c5ce2998d6c26eaeb5d6814a8f27 | |
| parent | f32f125b1c14dcde49ec415ec941af750433251e (diff) | |
cciss: factor out cciss_big_passthru
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
| -rw-r--r-- | drivers/block/cciss.c | 307 |
1 files changed, 151 insertions, 156 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 076dbcfa9471..cff2fa1972cb 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
| @@ -1498,6 +1498,155 @@ static int cciss_passthru(ctlr_info_t *h, void __user *argp) | |||
| 1498 | return 0; | 1498 | return 0; |
| 1499 | } | 1499 | } |
| 1500 | 1500 | ||
| 1501 | static int cciss_bigpassthru(ctlr_info_t *h, void __user *argp) | ||
| 1502 | { | ||
| 1503 | BIG_IOCTL_Command_struct *ioc; | ||
| 1504 | CommandList_struct *c; | ||
| 1505 | unsigned char **buff = NULL; | ||
| 1506 | int *buff_size = NULL; | ||
| 1507 | u64bit temp64; | ||
| 1508 | BYTE sg_used = 0; | ||
| 1509 | int status = 0; | ||
| 1510 | int i; | ||
| 1511 | DECLARE_COMPLETION_ONSTACK(wait); | ||
| 1512 | __u32 left; | ||
| 1513 | __u32 sz; | ||
| 1514 | BYTE __user *data_ptr; | ||
| 1515 | |||
| 1516 | if (!argp) | ||
| 1517 | return -EINVAL; | ||
| 1518 | if (!capable(CAP_SYS_RAWIO)) | ||
| 1519 | return -EPERM; | ||
| 1520 | ioc = (BIG_IOCTL_Command_struct *) | ||
| 1521 | kmalloc(sizeof(*ioc), GFP_KERNEL); | ||
| 1522 | if (!ioc) { | ||
| 1523 | status = -ENOMEM; | ||
| 1524 | goto cleanup1; | ||
| 1525 | } | ||
| 1526 | if (copy_from_user(ioc, argp, sizeof(*ioc))) { | ||
| 1527 | status = -EFAULT; | ||
| 1528 | goto cleanup1; | ||
| 1529 | } | ||
| 1530 | if ((ioc->buf_size < 1) && | ||
| 1531 | (ioc->Request.Type.Direction != XFER_NONE)) { | ||
| 1532 | status = -EINVAL; | ||
| 1533 | goto cleanup1; | ||
| 1534 | } | ||
| 1535 | /* Check kmalloc limits using all SGs */ | ||
| 1536 | if (ioc->malloc_size > MAX_KMALLOC_SIZE) { | ||
| 1537 | status = -EINVAL; | ||
| 1538 | goto cleanup1; | ||
| 1539 | } | ||
| 1540 | if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) { | ||
| 1541 | status = -EINVAL; | ||
| 1542 | goto cleanup1; | ||
| 1543 | } | ||
| 1544 | buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL); | ||
| 1545 | if (!buff) { | ||
| 1546 | status = -ENOMEM; | ||
| 1547 | goto cleanup1; | ||
| 1548 | } | ||
| 1549 | buff_size = kmalloc(MAXSGENTRIES * sizeof(int), GFP_KERNEL); | ||
| 1550 | if (!buff_size) { | ||
| 1551 | status = -ENOMEM; | ||
| 1552 | goto cleanup1; | ||
| 1553 | } | ||
| 1554 | left = ioc->buf_size; | ||
| 1555 | data_ptr = ioc->buf; | ||
| 1556 | while (left) { | ||
| 1557 | sz = (left > ioc->malloc_size) ? ioc->malloc_size : left; | ||
| 1558 | buff_size[sg_used] = sz; | ||
| 1559 | buff[sg_used] = kmalloc(sz, GFP_KERNEL); | ||
| 1560 | if (buff[sg_used] == NULL) { | ||
| 1561 | status = -ENOMEM; | ||
| 1562 | goto cleanup1; | ||
| 1563 | } | ||
| 1564 | if (ioc->Request.Type.Direction == XFER_WRITE) { | ||
| 1565 | if (copy_from_user(buff[sg_used], data_ptr, sz)) { | ||
| 1566 | status = -EFAULT; | ||
| 1567 | goto cleanup1; | ||
| 1568 | } | ||
| 1569 | } else { | ||
| 1570 | memset(buff[sg_used], 0, sz); | ||
| 1571 | } | ||
| 1572 | left -= sz; | ||
| 1573 | data_ptr += sz; | ||
| 1574 | sg_used++; | ||
| 1575 | } | ||
| 1576 | c = cmd_special_alloc(h); | ||
| 1577 | if (!c) { | ||
| 1578 | status = -ENOMEM; | ||
| 1579 | goto cleanup1; | ||
| 1580 | } | ||
| 1581 | c->cmd_type = CMD_IOCTL_PEND; | ||
| 1582 | c->Header.ReplyQueue = 0; | ||
| 1583 | |||
| 1584 | if (ioc->buf_size > 0) { | ||
| 1585 | c->Header.SGList = sg_used; | ||
| 1586 | c->Header.SGTotal = sg_used; | ||
| 1587 | } else { | ||
| 1588 | c->Header.SGList = 0; | ||
| 1589 | c->Header.SGTotal = 0; | ||
| 1590 | } | ||
| 1591 | c->Header.LUN = ioc->LUN_info; | ||
| 1592 | c->Header.Tag.lower = c->busaddr; | ||
| 1593 | |||
| 1594 | c->Request = ioc->Request; | ||
| 1595 | if (ioc->buf_size > 0) { | ||
| 1596 | for (i = 0; i < sg_used; i++) { | ||
| 1597 | temp64.val = | ||
| 1598 | pci_map_single(h->pdev, buff[i], buff_size[i], | ||
| 1599 | PCI_DMA_BIDIRECTIONAL); | ||
| 1600 | c->SG[i].Addr.lower = temp64.val32.lower; | ||
| 1601 | c->SG[i].Addr.upper = temp64.val32.upper; | ||
| 1602 | c->SG[i].Len = buff_size[i]; | ||
| 1603 | c->SG[i].Ext = 0; /* we are not chaining */ | ||
| 1604 | } | ||
| 1605 | } | ||
| 1606 | c->waiting = &wait; | ||
| 1607 | enqueue_cmd_and_start_io(h, c); | ||
| 1608 | wait_for_completion(&wait); | ||
| 1609 | /* unlock the buffers from DMA */ | ||
| 1610 | for (i = 0; i < sg_used; i++) { | ||
| 1611 | temp64.val32.lower = c->SG[i].Addr.lower; | ||
| 1612 | temp64.val32.upper = c->SG[i].Addr.upper; | ||
| 1613 | pci_unmap_single(h->pdev, | ||
| 1614 | (dma_addr_t) temp64.val, buff_size[i], | ||
| 1615 | PCI_DMA_BIDIRECTIONAL); | ||
| 1616 | } | ||
| 1617 | check_ioctl_unit_attention(h, c); | ||
| 1618 | /* Copy the error information out */ | ||
| 1619 | ioc->error_info = *(c->err_info); | ||
| 1620 | if (copy_to_user(argp, ioc, sizeof(*ioc))) { | ||
| 1621 | cmd_special_free(h, c); | ||
| 1622 | status = -EFAULT; | ||
| 1623 | goto cleanup1; | ||
| 1624 | } | ||
| 1625 | if (ioc->Request.Type.Direction == XFER_READ) { | ||
| 1626 | /* Copy the data out of the buffer we created */ | ||
| 1627 | BYTE __user *ptr = ioc->buf; | ||
| 1628 | for (i = 0; i < sg_used; i++) { | ||
| 1629 | if (copy_to_user(ptr, buff[i], buff_size[i])) { | ||
| 1630 | cmd_special_free(h, c); | ||
| 1631 | status = -EFAULT; | ||
| 1632 | goto cleanup1; | ||
| 1633 | } | ||
| 1634 | ptr += buff_size[i]; | ||
| 1635 | } | ||
| 1636 | } | ||
| 1637 | cmd_special_free(h, c); | ||
| 1638 | status = 0; | ||
| 1639 | cleanup1: | ||
| 1640 | if (buff) { | ||
| 1641 | for (i = 0; i < sg_used; i++) | ||
| 1642 | kfree(buff[i]); | ||
| 1643 | kfree(buff); | ||
| 1644 | } | ||
| 1645 | kfree(buff_size); | ||
| 1646 | kfree(ioc); | ||
| 1647 | return status; | ||
| 1648 | } | ||
| 1649 | |||
| 1501 | static int cciss_ioctl(struct block_device *bdev, fmode_t mode, | 1650 | static int cciss_ioctl(struct block_device *bdev, fmode_t mode, |
| 1502 | unsigned int cmd, unsigned long arg) | 1651 | unsigned int cmd, unsigned long arg) |
| 1503 | { | 1652 | { |
| @@ -1534,162 +1683,8 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, | |||
| 1534 | return cciss_getluninfo(h, disk, argp); | 1683 | return cciss_getluninfo(h, disk, argp); |
| 1535 | case CCISS_PASSTHRU: | 1684 | case CCISS_PASSTHRU: |
| 1536 | return cciss_passthru(h, argp); | 1685 | return cciss_passthru(h, argp); |
| 1537 | case CCISS_BIG_PASSTHRU:{ | 1686 | case CCISS_BIG_PASSTHRU: |
| 1538 | BIG_IOCTL_Command_struct *ioc; | 1687 | return cciss_bigpassthru(h, argp); |
| 1539 | CommandList_struct *c; | ||
| 1540 | unsigned char **buff = NULL; | ||
| 1541 | int *buff_size = NULL; | ||
| 1542 | u64bit temp64; | ||
| 1543 | BYTE sg_used = 0; | ||
| 1544 | int status = 0; | ||
| 1545 | int i; | ||
| 1546 | DECLARE_COMPLETION_ONSTACK(wait); | ||
| 1547 | __u32 left; | ||
| 1548 | __u32 sz; | ||
| 1549 | BYTE __user *data_ptr; | ||
| 1550 | |||
| 1551 | if (!arg) | ||
| 1552 | return -EINVAL; | ||
| 1553 | if (!capable(CAP_SYS_RAWIO)) | ||
| 1554 | return -EPERM; | ||
| 1555 | ioc = (BIG_IOCTL_Command_struct *) | ||
| 1556 | kmalloc(sizeof(*ioc), GFP_KERNEL); | ||
| 1557 | if (!ioc) { | ||
| 1558 | status = -ENOMEM; | ||
| 1559 | goto cleanup1; | ||
| 1560 | } | ||
| 1561 | if (copy_from_user(ioc, argp, sizeof(*ioc))) { | ||
| 1562 | status = -EFAULT; | ||
| 1563 | goto cleanup1; | ||
| 1564 | } | ||
| 1565 | if ((ioc->buf_size < 1) && | ||
| 1566 | (ioc->Request.Type.Direction != XFER_NONE)) { | ||
| 1567 | status = -EINVAL; | ||
| 1568 | goto cleanup1; | ||
| 1569 | } | ||
| 1570 | /* Check kmalloc limits using all SGs */ | ||
| 1571 | if (ioc->malloc_size > MAX_KMALLOC_SIZE) { | ||
| 1572 | status = -EINVAL; | ||
| 1573 | goto cleanup1; | ||
| 1574 | } | ||
| 1575 | if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) { | ||
| 1576 | status = -EINVAL; | ||
| 1577 | goto cleanup1; | ||
| 1578 | } | ||
| 1579 | buff = | ||
| 1580 | kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL); | ||
| 1581 | if (!buff) { | ||
| 1582 | status = -ENOMEM; | ||
| 1583 | goto cleanup1; | ||
| 1584 | } | ||
| 1585 | buff_size = kmalloc(MAXSGENTRIES * sizeof(int), | ||
| 1586 | GFP_KERNEL); | ||
| 1587 | if (!buff_size) { | ||
| 1588 | status = -ENOMEM; | ||
| 1589 | goto cleanup1; | ||
| 1590 | } | ||
| 1591 | left = ioc->buf_size; | ||
| 1592 | data_ptr = ioc->buf; | ||
| 1593 | while (left) { | ||
| 1594 | sz = (left > | ||
| 1595 | ioc->malloc_size) ? ioc-> | ||
| 1596 | malloc_size : left; | ||
| 1597 | buff_size[sg_used] = sz; | ||
| 1598 | buff[sg_used] = kmalloc(sz, GFP_KERNEL); | ||
| 1599 | if (buff[sg_used] == NULL) { | ||
| 1600 | status = -ENOMEM; | ||
| 1601 | goto cleanup1; | ||
| 1602 | } | ||
| 1603 | if (ioc->Request.Type.Direction == XFER_WRITE) { | ||
| 1604 | if (copy_from_user | ||
| 1605 | (buff[sg_used], data_ptr, sz)) { | ||
| 1606 | status = -EFAULT; | ||
| 1607 | goto cleanup1; | ||
| 1608 | } | ||
| 1609 | } else { | ||
| 1610 | memset(buff[sg_used], 0, sz); | ||
| 1611 | } | ||
| 1612 | left -= sz; | ||
| 1613 | data_ptr += sz; | ||
| 1614 | sg_used++; | ||
| 1615 | } | ||
| 1616 | c = cmd_special_alloc(h); | ||
| 1617 | if (!c) { | ||
| 1618 | status = -ENOMEM; | ||
| 1619 | goto cleanup1; | ||
| 1620 | } | ||
| 1621 | c->cmd_type = CMD_IOCTL_PEND; | ||
| 1622 | c->Header.ReplyQueue = 0; | ||
| 1623 | |||
| 1624 | if (ioc->buf_size > 0) { | ||
| 1625 | c->Header.SGList = sg_used; | ||
| 1626 | c->Header.SGTotal = sg_used; | ||
| 1627 | } else { | ||
| 1628 | c->Header.SGList = 0; | ||
| 1629 | c->Header.SGTotal = 0; | ||
| 1630 | } | ||
| 1631 | c->Header.LUN = ioc->LUN_info; | ||
| 1632 | c->Header.Tag.lower = c->busaddr; | ||
| 1633 | |||
| 1634 | c->Request = ioc->Request; | ||
| 1635 | if (ioc->buf_size > 0) { | ||
| 1636 | for (i = 0; i < sg_used; i++) { | ||
| 1637 | temp64.val = | ||
| 1638 | pci_map_single(h->pdev, buff[i], | ||
| 1639 | buff_size[i], | ||
| 1640 | PCI_DMA_BIDIRECTIONAL); | ||
| 1641 | c->SG[i].Addr.lower = | ||
| 1642 | temp64.val32.lower; | ||
| 1643 | c->SG[i].Addr.upper = | ||
| 1644 | temp64.val32.upper; | ||
| 1645 | c->SG[i].Len = buff_size[i]; | ||
| 1646 | c->SG[i].Ext = 0; /* we are not chaining */ | ||
| 1647 | } | ||
| 1648 | } | ||
| 1649 | c->waiting = &wait; | ||
| 1650 | enqueue_cmd_and_start_io(h, c); | ||
| 1651 | wait_for_completion(&wait); | ||
| 1652 | /* unlock the buffers from DMA */ | ||
| 1653 | for (i = 0; i < sg_used; i++) { | ||
| 1654 | temp64.val32.lower = c->SG[i].Addr.lower; | ||
| 1655 | temp64.val32.upper = c->SG[i].Addr.upper; | ||
| 1656 | pci_unmap_single(h->pdev, | ||
| 1657 | (dma_addr_t) temp64.val, buff_size[i], | ||
| 1658 | PCI_DMA_BIDIRECTIONAL); | ||
| 1659 | } | ||
| 1660 | check_ioctl_unit_attention(h, c); | ||
| 1661 | /* Copy the error information out */ | ||
| 1662 | ioc->error_info = *(c->err_info); | ||
| 1663 | if (copy_to_user(argp, ioc, sizeof(*ioc))) { | ||
| 1664 | cmd_special_free(h, c); | ||
| 1665 | status = -EFAULT; | ||
| 1666 | goto cleanup1; | ||
| 1667 | } | ||
| 1668 | if (ioc->Request.Type.Direction == XFER_READ) { | ||
| 1669 | /* Copy the data out of the buffer we created */ | ||
| 1670 | BYTE __user *ptr = ioc->buf; | ||
| 1671 | for (i = 0; i < sg_used; i++) { | ||
| 1672 | if (copy_to_user | ||
| 1673 | (ptr, buff[i], buff_size[i])) { | ||
| 1674 | cmd_special_free(h, c); | ||
| 1675 | status = -EFAULT; | ||
| 1676 | goto cleanup1; | ||
| 1677 | } | ||
| 1678 | ptr += buff_size[i]; | ||
| 1679 | } | ||
| 1680 | } | ||
| 1681 | cmd_special_free(h, c); | ||
| 1682 | status = 0; | ||
| 1683 | cleanup1: | ||
| 1684 | if (buff) { | ||
| 1685 | for (i = 0; i < sg_used; i++) | ||
| 1686 | kfree(buff[i]); | ||
| 1687 | kfree(buff); | ||
| 1688 | } | ||
| 1689 | kfree(buff_size); | ||
| 1690 | kfree(ioc); | ||
| 1691 | return status; | ||
| 1692 | } | ||
| 1693 | 1688 | ||
| 1694 | /* scsi_cmd_ioctl handles these, below, though some are not */ | 1689 | /* scsi_cmd_ioctl handles these, below, though some are not */ |
| 1695 | /* very meaningful for cciss. SG_IO is the main one people want. */ | 1690 | /* very meaningful for cciss. SG_IO is the main one people want. */ |
