diff options
author | Kashyap, Desai <kashyap.desai@lsi.com> | 2010-06-17 04:13:17 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-27 13:02:14 -0400 |
commit | 570c67ac443dab5c46e5744e950f0539724cb65d (patch) | |
tree | dad14200b33f9c0d24c43886b7a88b2a7bf0f2eb /drivers/scsi/mpt2sas | |
parent | 203d65b16cfef448dbfb79f66b672be4511fc6a9 (diff) |
[SCSI] mpt2sas: Added sysfs support for trace buffer
Added support so the diag ring buffer can be pulled via sysfs
Added three new shost attributes: host_trace_buffer,
host_trace_buffer_enable, and host_trace_buffer_size. The
host_trace_buffer_enable attribute is used to either post or release
the trace buffers. The host_trace_buffer_size attribute contains
the size of the trace buffer. The host_trace_buffer atttribute contains
a maximum 4KB window of the buffer. In order to read the entire host buffer,
you will need to write the offset to host_trace_buffer prior to reading
it. release the host buffer, then write the entire host buffer contents to
a file.
In addition to this enhancement, we moved the automatic posting of host buffers
at driver load time to be called prior to port_enable, instead of after.
That way discovery is available in the host buffer.
Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/mpt2sas')
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.c | 10 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.h | 2 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.c | 192 |
3 files changed, 200 insertions, 4 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 88befc798469..93c06239d951 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c | |||
@@ -3529,8 +3529,12 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
3529 | if (sleep_flag == CAN_SLEEP) | 3529 | if (sleep_flag == CAN_SLEEP) |
3530 | _base_static_config_pages(ioc); | 3530 | _base_static_config_pages(ioc); |
3531 | 3531 | ||
3532 | if (ioc->wait_for_port_enable_to_complete && disable_discovery > 0) | 3532 | if (ioc->wait_for_port_enable_to_complete) { |
3533 | return r; | 3533 | if (diag_buffer_enable != 0) |
3534 | mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); | ||
3535 | if (disable_discovery > 0) | ||
3536 | return r; | ||
3537 | } | ||
3534 | 3538 | ||
3535 | r = _base_send_port_enable(ioc, sleep_flag); | 3539 | r = _base_send_port_enable(ioc, sleep_flag); |
3536 | if (r) | 3540 | if (r) |
@@ -3679,8 +3683,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) | |||
3679 | goto out_free_resources; | 3683 | goto out_free_resources; |
3680 | 3684 | ||
3681 | mpt2sas_base_start_watchdog(ioc); | 3685 | mpt2sas_base_start_watchdog(ioc); |
3682 | if (diag_buffer_enable != 0) | ||
3683 | mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); | ||
3684 | return 0; | 3686 | return 0; |
3685 | 3687 | ||
3686 | out_free_resources: | 3688 | out_free_resources: |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index a4a731529226..ffe93984e56a 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h | |||
@@ -750,6 +750,8 @@ struct MPT2SAS_ADAPTER { | |||
750 | Mpi2ManufacturingPage10_t manu_pg10; | 750 | Mpi2ManufacturingPage10_t manu_pg10; |
751 | u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23]; | 751 | u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23]; |
752 | u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; | 752 | u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; |
753 | u32 ring_buffer_offset; | ||
754 | u32 ring_buffer_sz; | ||
753 | }; | 755 | }; |
754 | 756 | ||
755 | typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, | 757 | typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 25c866e3e900..371f063a926c 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c | |||
@@ -2603,6 +2603,195 @@ _ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, | |||
2603 | static DEVICE_ATTR(ioc_reset_count, S_IRUGO, | 2603 | static DEVICE_ATTR(ioc_reset_count, S_IRUGO, |
2604 | _ctl_ioc_reset_count_show, NULL); | 2604 | _ctl_ioc_reset_count_show, NULL); |
2605 | 2605 | ||
2606 | struct DIAG_BUFFER_START { | ||
2607 | u32 Size; | ||
2608 | u32 DiagVersion; | ||
2609 | u8 BufferType; | ||
2610 | u8 Reserved[3]; | ||
2611 | u32 Reserved1; | ||
2612 | u32 Reserved2; | ||
2613 | u32 Reserved3; | ||
2614 | }; | ||
2615 | /** | ||
2616 | * _ctl_host_trace_buffer_size_show - host buffer size (trace only) | ||
2617 | * @cdev - pointer to embedded class device | ||
2618 | * @buf - the buffer returned | ||
2619 | * | ||
2620 | * A sysfs 'read-only' shost attribute. | ||
2621 | */ | ||
2622 | static ssize_t | ||
2623 | _ctl_host_trace_buffer_size_show(struct device *cdev, | ||
2624 | struct device_attribute *attr, char *buf) | ||
2625 | { | ||
2626 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2627 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2628 | u32 size = 0; | ||
2629 | struct DIAG_BUFFER_START *request_data; | ||
2630 | |||
2631 | if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { | ||
2632 | printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " | ||
2633 | "registered\n", ioc->name, __func__); | ||
2634 | return 0; | ||
2635 | } | ||
2636 | |||
2637 | if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & | ||
2638 | MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { | ||
2639 | printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " | ||
2640 | "registered\n", ioc->name, __func__); | ||
2641 | return 0; | ||
2642 | } | ||
2643 | |||
2644 | request_data = (struct DIAG_BUFFER_START *) | ||
2645 | ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]; | ||
2646 | if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 || | ||
2647 | le32_to_cpu(request_data->DiagVersion) == 0x01000000) && | ||
2648 | le32_to_cpu(request_data->Reserved3) == 0x4742444c) | ||
2649 | size = le32_to_cpu(request_data->Size); | ||
2650 | |||
2651 | ioc->ring_buffer_sz = size; | ||
2652 | return snprintf(buf, PAGE_SIZE, "%d\n", size); | ||
2653 | } | ||
2654 | static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO, | ||
2655 | _ctl_host_trace_buffer_size_show, NULL); | ||
2656 | |||
2657 | /** | ||
2658 | * _ctl_host_trace_buffer_show - firmware ring buffer (trace only) | ||
2659 | * @cdev - pointer to embedded class device | ||
2660 | * @buf - the buffer returned | ||
2661 | * | ||
2662 | * A sysfs 'read/write' shost attribute. | ||
2663 | * | ||
2664 | * You will only be able to read 4k bytes of ring buffer at a time. | ||
2665 | * In order to read beyond 4k bytes, you will have to write out the | ||
2666 | * offset to the same attribute, it will move the pointer. | ||
2667 | */ | ||
2668 | static ssize_t | ||
2669 | _ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, | ||
2670 | char *buf) | ||
2671 | { | ||
2672 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2673 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2674 | void *request_data; | ||
2675 | u32 size; | ||
2676 | |||
2677 | if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { | ||
2678 | printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " | ||
2679 | "registered\n", ioc->name, __func__); | ||
2680 | return 0; | ||
2681 | } | ||
2682 | |||
2683 | if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & | ||
2684 | MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { | ||
2685 | printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " | ||
2686 | "registered\n", ioc->name, __func__); | ||
2687 | return 0; | ||
2688 | } | ||
2689 | |||
2690 | if (ioc->ring_buffer_offset > ioc->ring_buffer_sz) | ||
2691 | return 0; | ||
2692 | |||
2693 | size = ioc->ring_buffer_sz - ioc->ring_buffer_offset; | ||
2694 | size = (size > PAGE_SIZE) ? PAGE_SIZE : size; | ||
2695 | request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset; | ||
2696 | memcpy(buf, request_data, size); | ||
2697 | return size; | ||
2698 | } | ||
2699 | |||
2700 | static ssize_t | ||
2701 | _ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, | ||
2702 | const char *buf, size_t count) | ||
2703 | { | ||
2704 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2705 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2706 | int val = 0; | ||
2707 | |||
2708 | if (sscanf(buf, "%d", &val) != 1) | ||
2709 | return -EINVAL; | ||
2710 | |||
2711 | ioc->ring_buffer_offset = val; | ||
2712 | return strlen(buf); | ||
2713 | } | ||
2714 | static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR, | ||
2715 | _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store); | ||
2716 | |||
2717 | /*****************************************/ | ||
2718 | |||
2719 | /** | ||
2720 | * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only) | ||
2721 | * @cdev - pointer to embedded class device | ||
2722 | * @buf - the buffer returned | ||
2723 | * | ||
2724 | * A sysfs 'read/write' shost attribute. | ||
2725 | * | ||
2726 | * This is a mechnism to post/release host_trace_buffers | ||
2727 | */ | ||
2728 | static ssize_t | ||
2729 | _ctl_host_trace_buffer_enable_show(struct device *cdev, | ||
2730 | struct device_attribute *attr, char *buf) | ||
2731 | { | ||
2732 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2733 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2734 | |||
2735 | if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) || | ||
2736 | ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & | ||
2737 | MPT2_DIAG_BUFFER_IS_REGISTERED) == 0)) | ||
2738 | return snprintf(buf, PAGE_SIZE, "off\n"); | ||
2739 | else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & | ||
2740 | MPT2_DIAG_BUFFER_IS_RELEASED)) | ||
2741 | return snprintf(buf, PAGE_SIZE, "release\n"); | ||
2742 | else | ||
2743 | return snprintf(buf, PAGE_SIZE, "post\n"); | ||
2744 | } | ||
2745 | |||
2746 | static ssize_t | ||
2747 | _ctl_host_trace_buffer_enable_store(struct device *cdev, | ||
2748 | struct device_attribute *attr, const char *buf, size_t count) | ||
2749 | { | ||
2750 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2751 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2752 | char str[10] = ""; | ||
2753 | struct mpt2_diag_register diag_register; | ||
2754 | u8 issue_reset = 0; | ||
2755 | |||
2756 | if (sscanf(buf, "%s", str) != 1) | ||
2757 | return -EINVAL; | ||
2758 | |||
2759 | if (!strcmp(str, "post")) { | ||
2760 | /* exit out if host buffers are already posted */ | ||
2761 | if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) && | ||
2762 | (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & | ||
2763 | MPT2_DIAG_BUFFER_IS_REGISTERED) && | ||
2764 | ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & | ||
2765 | MPT2_DIAG_BUFFER_IS_RELEASED) == 0)) | ||
2766 | goto out; | ||
2767 | memset(&diag_register, 0, sizeof(struct mpt2_diag_register)); | ||
2768 | printk(MPT2SAS_INFO_FMT "posting host trace buffers\n", | ||
2769 | ioc->name); | ||
2770 | diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; | ||
2771 | diag_register.requested_buffer_size = (1024 * 1024); | ||
2772 | diag_register.unique_id = 0x7075900; | ||
2773 | ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0; | ||
2774 | _ctl_diag_register_2(ioc, &diag_register); | ||
2775 | } else if (!strcmp(str, "release")) { | ||
2776 | /* exit out if host buffers are already released */ | ||
2777 | if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) | ||
2778 | goto out; | ||
2779 | if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & | ||
2780 | MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) | ||
2781 | goto out; | ||
2782 | if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & | ||
2783 | MPT2_DIAG_BUFFER_IS_RELEASED)) | ||
2784 | goto out; | ||
2785 | printk(MPT2SAS_INFO_FMT "releasing host trace buffer\n", | ||
2786 | ioc->name); | ||
2787 | _ctl_send_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset); | ||
2788 | } | ||
2789 | |||
2790 | out: | ||
2791 | return strlen(buf); | ||
2792 | } | ||
2793 | static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR, | ||
2794 | _ctl_host_trace_buffer_enable_show, _ctl_host_trace_buffer_enable_store); | ||
2606 | 2795 | ||
2607 | struct device_attribute *mpt2sas_host_attrs[] = { | 2796 | struct device_attribute *mpt2sas_host_attrs[] = { |
2608 | &dev_attr_version_fw, | 2797 | &dev_attr_version_fw, |
@@ -2621,6 +2810,9 @@ struct device_attribute *mpt2sas_host_attrs[] = { | |||
2621 | &dev_attr_fw_queue_depth, | 2810 | &dev_attr_fw_queue_depth, |
2622 | &dev_attr_host_sas_address, | 2811 | &dev_attr_host_sas_address, |
2623 | &dev_attr_ioc_reset_count, | 2812 | &dev_attr_ioc_reset_count, |
2813 | &dev_attr_host_trace_buffer_size, | ||
2814 | &dev_attr_host_trace_buffer, | ||
2815 | &dev_attr_host_trace_buffer_enable, | ||
2624 | NULL, | 2816 | NULL, |
2625 | }; | 2817 | }; |
2626 | 2818 | ||