diff options
author | Eric Moore <eric.moore@lsi.com> | 2009-04-21 17:42:13 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-04-27 11:54:04 -0400 |
commit | 99bb214b1b652c475bb3d79cede47ecb76b758fa (patch) | |
tree | e9e540c07496b8388c03ea8bf279a71089353200 /drivers/scsi/mpt2sas | |
parent | 8901cbb45e2a6657adf0e6eea4276ef452dee011 (diff) |
[SCSI] mpt2sas : release diagnotic buffers prior host reset
Diagnostic buffer support is already there in the driver. This support allows
applications to pull ring buffers from controller firmware for debugging
firmware related issues.
What this patch does is sends reqeust to firmware to release the buffers prior
to host reset. This will allow what ever debug info is there prior to reset
to be dma'd to host memory. With out this fix, some of the debug data would
been lost.
Signed-off-by: Eric Moore <eric.moore@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
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) |