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) |