diff options
Diffstat (limited to 'drivers/scsi/mpt2sas')
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.c | 206 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.h | 5 |
2 files changed, 141 insertions, 70 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 2dc38598c207..ba6ab170bdf0 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c | |||
| @@ -64,6 +64,9 @@ | |||
| 64 | static struct fasync_struct *async_queue; | 64 | static struct fasync_struct *async_queue; |
| 65 | static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait); | 65 | static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait); |
| 66 | 66 | ||
| 67 | static int _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, | ||
| 68 | u8 *issue_reset); | ||
| 69 | |||
| 67 | /** | 70 | /** |
| 68 | * enum block_state - blocking state | 71 | * enum block_state - blocking state |
| 69 | * @NON_BLOCKING: non blocking | 72 | * @NON_BLOCKING: non blocking |
| @@ -378,10 +381,22 @@ _ctl_verify_adapter(int ioc_number, struct MPT2SAS_ADAPTER **iocpp) | |||
| 378 | void | 381 | void |
| 379 | mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) | 382 | mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) |
| 380 | { | 383 | { |
| 384 | int i; | ||
| 385 | u8 issue_reset; | ||
| 386 | |||
| 381 | switch (reset_phase) { | 387 | switch (reset_phase) { |
| 382 | case MPT2_IOC_PRE_RESET: | 388 | case MPT2_IOC_PRE_RESET: |
| 383 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " | 389 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " |
| 384 | "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); | 390 | "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); |
| 391 | for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { | ||
| 392 | if (!(ioc->diag_buffer_status[i] & | ||
| 393 | MPT2_DIAG_BUFFER_IS_REGISTERED)) | ||
| 394 | continue; | ||
| 395 | if ((ioc->diag_buffer_status[i] & | ||
| 396 | MPT2_DIAG_BUFFER_IS_RELEASED)) | ||
| 397 | continue; | ||
| 398 | _ctl_send_release(ioc, i, &issue_reset); | ||
| 399 | } | ||
| 385 | break; | 400 | break; |
| 386 | case MPT2_IOC_AFTER_RESET: | 401 | case MPT2_IOC_AFTER_RESET: |
| 387 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " | 402 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " |
| @@ -395,6 +410,17 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) | |||
| 395 | case MPT2_IOC_DONE_RESET: | 410 | case MPT2_IOC_DONE_RESET: |
| 396 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " | 411 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " |
| 397 | "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); | 412 | "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); |
| 413 | |||
| 414 | for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { | ||
| 415 | if (!(ioc->diag_buffer_status[i] & | ||
| 416 | MPT2_DIAG_BUFFER_IS_REGISTERED)) | ||
| 417 | continue; | ||
| 418 | if ((ioc->diag_buffer_status[i] & | ||
| 419 | MPT2_DIAG_BUFFER_IS_RELEASED)) | ||
| 420 | continue; | ||
| 421 | ioc->diag_buffer_status[i] |= | ||
| 422 | MPT2_DIAG_BUFFER_IS_DIAG_RESET; | ||
| 423 | } | ||
| 398 | break; | 424 | break; |
| 399 | } | 425 | } |
| 400 | } | 426 | } |
| @@ -1553,81 +1579,38 @@ _ctl_diag_query(void __user *arg) | |||
| 1553 | } | 1579 | } |
| 1554 | 1580 | ||
| 1555 | /** | 1581 | /** |
| 1556 | * _ctl_diag_release - request to send Diag Release Message to firmware | 1582 | * _ctl_send_release - Diag Release Message |
| 1557 | * @arg - user space buffer containing ioctl content | 1583 | * @ioc: per adapter object |
| 1558 | * @state - NON_BLOCKING or BLOCKING | 1584 | * @buffer_type - specifies either TRACE or SNAPSHOT |
| 1585 | * @issue_reset - specifies whether host reset is required. | ||
| 1559 | * | 1586 | * |
| 1560 | * This allows ownership of the specified buffer to returned to the driver, | ||
| 1561 | * allowing an application to read the buffer without fear that firmware is | ||
| 1562 | * overwritting information in the buffer. | ||
| 1563 | */ | 1587 | */ |
| 1564 | static long | 1588 | static int |
| 1565 | _ctl_diag_release(void __user *arg, enum block_state state) | 1589 | _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) |
| 1566 | { | 1590 | { |
| 1567 | struct mpt2_diag_release karg; | ||
| 1568 | struct MPT2SAS_ADAPTER *ioc; | ||
| 1569 | void *request_data; | ||
| 1570 | int rc; | ||
| 1571 | Mpi2DiagReleaseRequest_t *mpi_request; | 1591 | Mpi2DiagReleaseRequest_t *mpi_request; |
| 1572 | Mpi2DiagReleaseReply_t *mpi_reply; | 1592 | Mpi2DiagReleaseReply_t *mpi_reply; |
| 1573 | u8 buffer_type; | ||
| 1574 | unsigned long timeleft; | ||
| 1575 | u16 smid; | 1593 | u16 smid; |
| 1576 | u16 ioc_status; | 1594 | u16 ioc_status; |
| 1577 | u8 issue_reset = 0; | 1595 | u32 ioc_state; |
| 1578 | 1596 | int rc; | |
| 1579 | if (copy_from_user(&karg, arg, sizeof(karg))) { | 1597 | unsigned long timeleft; |
| 1580 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
| 1581 | __FILE__, __LINE__, __func__); | ||
| 1582 | return -EFAULT; | ||
| 1583 | } | ||
| 1584 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
| 1585 | return -ENODEV; | ||
| 1586 | 1598 | ||
| 1587 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, | 1599 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, |
| 1588 | __func__)); | 1600 | __func__)); |
| 1589 | 1601 | ||
| 1590 | buffer_type = karg.unique_id & 0x000000ff; | 1602 | rc = 0; |
| 1591 | if (!_ctl_diag_capability(ioc, buffer_type)) { | 1603 | *issue_reset = 0; |
| 1592 | printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " | ||
| 1593 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); | ||
| 1594 | return -EPERM; | ||
| 1595 | } | ||
| 1596 | |||
| 1597 | if ((ioc->diag_buffer_status[buffer_type] & | ||
| 1598 | MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { | ||
| 1599 | printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " | ||
| 1600 | "registered\n", ioc->name, __func__, buffer_type); | ||
| 1601 | return -EINVAL; | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | if (karg.unique_id != ioc->unique_id[buffer_type]) { | ||
| 1605 | printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " | ||
| 1606 | "registered\n", ioc->name, __func__, karg.unique_id); | ||
| 1607 | return -EINVAL; | ||
| 1608 | } | ||
| 1609 | |||
| 1610 | if (ioc->diag_buffer_status[buffer_type] & | ||
| 1611 | MPT2_DIAG_BUFFER_IS_RELEASED) { | ||
| 1612 | printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) " | ||
| 1613 | "is already released\n", ioc->name, __func__, | ||
| 1614 | buffer_type); | ||
| 1615 | return 0; | ||
| 1616 | } | ||
| 1617 | |||
| 1618 | request_data = ioc->diag_buffer[buffer_type]; | ||
| 1619 | 1604 | ||
| 1620 | if (!request_data) { | 1605 | ioc_state = mpt2sas_base_get_iocstate(ioc, 1); |
| 1621 | printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for " | 1606 | if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { |
| 1622 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); | 1607 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " |
| 1623 | return -ENOMEM; | 1608 | "skipping due to FAULT state\n", ioc->name, |
| 1609 | __func__)); | ||
| 1610 | rc = -EAGAIN; | ||
| 1611 | goto out; | ||
| 1624 | } | 1612 | } |
| 1625 | 1613 | ||
| 1626 | if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) | ||
| 1627 | return -EAGAIN; | ||
| 1628 | else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) | ||
| 1629 | return -ERESTARTSYS; | ||
| 1630 | |||
| 1631 | if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { | 1614 | if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { |
| 1632 | printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", | 1615 | printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", |
| 1633 | ioc->name, __func__); | 1616 | ioc->name, __func__); |
| @@ -1643,7 +1626,6 @@ _ctl_diag_release(void __user *arg, enum block_state state) | |||
| 1643 | goto out; | 1626 | goto out; |
| 1644 | } | 1627 | } |
| 1645 | 1628 | ||
| 1646 | rc = 0; | ||
| 1647 | ioc->ctl_cmds.status = MPT2_CMD_PENDING; | 1629 | ioc->ctl_cmds.status = MPT2_CMD_PENDING; |
| 1648 | memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); | 1630 | memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); |
| 1649 | mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); | 1631 | mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); |
| @@ -1662,8 +1644,9 @@ _ctl_diag_release(void __user *arg, enum block_state state) | |||
| 1662 | _debug_dump_mf(mpi_request, | 1644 | _debug_dump_mf(mpi_request, |
| 1663 | sizeof(Mpi2DiagReleaseRequest_t)/4); | 1645 | sizeof(Mpi2DiagReleaseRequest_t)/4); |
| 1664 | if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) | 1646 | if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) |
| 1665 | issue_reset = 1; | 1647 | *issue_reset = 1; |
| 1666 | goto issue_host_reset; | 1648 | rc = -EFAULT; |
| 1649 | goto out; | ||
| 1667 | } | 1650 | } |
| 1668 | 1651 | ||
| 1669 | /* process the completed Reply Message Frame */ | 1652 | /* process the completed Reply Message Frame */ |
| @@ -1689,14 +1672,101 @@ _ctl_diag_release(void __user *arg, enum block_state state) | |||
| 1689 | rc = -EFAULT; | 1672 | rc = -EFAULT; |
| 1690 | } | 1673 | } |
| 1691 | 1674 | ||
| 1692 | issue_host_reset: | 1675 | out: |
| 1676 | ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; | ||
| 1677 | return rc; | ||
| 1678 | } | ||
| 1679 | |||
| 1680 | /** | ||
| 1681 | * _ctl_diag_release - request to send Diag Release Message to firmware | ||
| 1682 | * @arg - user space buffer containing ioctl content | ||
| 1683 | * @state - NON_BLOCKING or BLOCKING | ||
| 1684 | * | ||
| 1685 | * This allows ownership of the specified buffer to returned to the driver, | ||
| 1686 | * allowing an application to read the buffer without fear that firmware is | ||
| 1687 | * overwritting information in the buffer. | ||
| 1688 | */ | ||
| 1689 | static long | ||
| 1690 | _ctl_diag_release(void __user *arg, enum block_state state) | ||
| 1691 | { | ||
| 1692 | struct mpt2_diag_release karg; | ||
| 1693 | struct MPT2SAS_ADAPTER *ioc; | ||
| 1694 | void *request_data; | ||
| 1695 | int rc; | ||
| 1696 | u8 buffer_type; | ||
| 1697 | u8 issue_reset = 0; | ||
| 1698 | |||
| 1699 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
| 1700 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
| 1701 | __FILE__, __LINE__, __func__); | ||
| 1702 | return -EFAULT; | ||
| 1703 | } | ||
| 1704 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
| 1705 | return -ENODEV; | ||
| 1706 | |||
| 1707 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, | ||
| 1708 | __func__)); | ||
| 1709 | |||
| 1710 | buffer_type = karg.unique_id & 0x000000ff; | ||
| 1711 | if (!_ctl_diag_capability(ioc, buffer_type)) { | ||
| 1712 | printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " | ||
| 1713 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); | ||
| 1714 | return -EPERM; | ||
| 1715 | } | ||
| 1716 | |||
| 1717 | if ((ioc->diag_buffer_status[buffer_type] & | ||
| 1718 | MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { | ||
| 1719 | printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " | ||
| 1720 | "registered\n", ioc->name, __func__, buffer_type); | ||
| 1721 | return -EINVAL; | ||
| 1722 | } | ||
| 1723 | |||
| 1724 | if (karg.unique_id != ioc->unique_id[buffer_type]) { | ||
| 1725 | printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " | ||
| 1726 | "registered\n", ioc->name, __func__, karg.unique_id); | ||
| 1727 | return -EINVAL; | ||
| 1728 | } | ||
| 1729 | |||
| 1730 | if (ioc->diag_buffer_status[buffer_type] & | ||
| 1731 | MPT2_DIAG_BUFFER_IS_RELEASED) { | ||
| 1732 | printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) " | ||
| 1733 | "is already released\n", ioc->name, __func__, | ||
| 1734 | buffer_type); | ||
| 1735 | return 0; | ||
| 1736 | } | ||
| 1737 | |||
| 1738 | request_data = ioc->diag_buffer[buffer_type]; | ||
| 1739 | |||
| 1740 | if (!request_data) { | ||
| 1741 | printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for " | ||
| 1742 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); | ||
| 1743 | return -ENOMEM; | ||
| 1744 | } | ||
| 1745 | |||
| 1746 | /* buffers were released by due to host reset */ | ||
| 1747 | if ((ioc->diag_buffer_status[buffer_type] & | ||
| 1748 | MPT2_DIAG_BUFFER_IS_DIAG_RESET)) { | ||
| 1749 | ioc->diag_buffer_status[buffer_type] |= | ||
| 1750 | MPT2_DIAG_BUFFER_IS_RELEASED; | ||
| 1751 | ioc->diag_buffer_status[buffer_type] &= | ||
| 1752 | ~MPT2_DIAG_BUFFER_IS_DIAG_RESET; | ||
| 1753 | printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) " | ||
| 1754 | "was released due to host reset\n", ioc->name, __func__, | ||
| 1755 | buffer_type); | ||
| 1756 | return 0; | ||
| 1757 | } | ||
| 1758 | |||
| 1759 | if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) | ||
| 1760 | return -EAGAIN; | ||
| 1761 | else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) | ||
| 1762 | return -ERESTARTSYS; | ||
| 1763 | |||
| 1764 | rc = _ctl_send_release(ioc, buffer_type, &issue_reset); | ||
| 1765 | |||
| 1693 | if (issue_reset) | 1766 | if (issue_reset) |
| 1694 | mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, | 1767 | mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, |
| 1695 | FORCE_BIG_HAMMER); | 1768 | FORCE_BIG_HAMMER); |
| 1696 | 1769 | ||
| 1697 | out: | ||
| 1698 | |||
| 1699 | ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; | ||
| 1700 | mutex_unlock(&ioc->ctl_cmds.mutex); | 1770 | mutex_unlock(&ioc->ctl_cmds.mutex); |
| 1701 | return rc; | 1771 | return rc; |
| 1702 | } | 1772 | } |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h index 5bd7d4cfa819..4da11435533f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h | |||
| @@ -295,8 +295,9 @@ struct mpt2_ioctl_btdh_mapping { | |||
| 295 | 295 | ||
| 296 | 296 | ||
| 297 | /* status bits for ioc->diag_buffer_status */ | 297 | /* status bits for ioc->diag_buffer_status */ |
| 298 | #define MPT2_DIAG_BUFFER_IS_REGISTERED (0x01) | 298 | #define MPT2_DIAG_BUFFER_IS_REGISTERED (0x01) |
| 299 | #define MPT2_DIAG_BUFFER_IS_RELEASED (0x02) | 299 | #define MPT2_DIAG_BUFFER_IS_RELEASED (0x02) |
| 300 | #define MPT2_DIAG_BUFFER_IS_DIAG_RESET (0x04) | ||
| 300 | 301 | ||
| 301 | /* application flags for mpt2_diag_register, mpt2_diag_query */ | 302 | /* application flags for mpt2_diag_register, mpt2_diag_query */ |
| 302 | #define MPT2_APP_FLAGS_APP_OWNED (0x0001) | 303 | #define MPT2_APP_FLAGS_APP_OWNED (0x0001) |
