diff options
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_attr.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_attr.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_attr.c b/drivers/scsi/qla4xxx/ql4_attr.c index 0b0a7d42137d..c681b2a355e1 100644 --- a/drivers/scsi/qla4xxx/ql4_attr.c +++ b/drivers/scsi/qla4xxx/ql4_attr.c | |||
@@ -9,6 +9,140 @@ | |||
9 | #include "ql4_glbl.h" | 9 | #include "ql4_glbl.h" |
10 | #include "ql4_dbg.h" | 10 | #include "ql4_dbg.h" |
11 | 11 | ||
12 | static ssize_t | ||
13 | qla4_8xxx_sysfs_read_fw_dump(struct file *filep, struct kobject *kobj, | ||
14 | struct bin_attribute *ba, char *buf, loff_t off, | ||
15 | size_t count) | ||
16 | { | ||
17 | struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, | ||
18 | struct device, kobj))); | ||
19 | |||
20 | if (!is_qla8022(ha)) | ||
21 | return -EINVAL; | ||
22 | |||
23 | if (!test_bit(AF_82XX_DUMP_READING, &ha->flags)) | ||
24 | return 0; | ||
25 | |||
26 | return memory_read_from_buffer(buf, count, &off, ha->fw_dump, | ||
27 | ha->fw_dump_size); | ||
28 | } | ||
29 | |||
30 | static ssize_t | ||
31 | qla4_8xxx_sysfs_write_fw_dump(struct file *filep, struct kobject *kobj, | ||
32 | struct bin_attribute *ba, char *buf, loff_t off, | ||
33 | size_t count) | ||
34 | { | ||
35 | struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, | ||
36 | struct device, kobj))); | ||
37 | uint32_t dev_state; | ||
38 | long reading; | ||
39 | int ret = 0; | ||
40 | |||
41 | if (!is_qla8022(ha)) | ||
42 | return -EINVAL; | ||
43 | |||
44 | if (off != 0) | ||
45 | return ret; | ||
46 | |||
47 | buf[1] = 0; | ||
48 | ret = kstrtol(buf, 10, &reading); | ||
49 | if (ret) { | ||
50 | ql4_printk(KERN_ERR, ha, "%s: Invalid input. Return err %d\n", | ||
51 | __func__, ret); | ||
52 | return ret; | ||
53 | } | ||
54 | |||
55 | switch (reading) { | ||
56 | case 0: | ||
57 | /* clear dump collection flags */ | ||
58 | if (test_and_clear_bit(AF_82XX_DUMP_READING, &ha->flags)) { | ||
59 | clear_bit(AF_82XX_FW_DUMPED, &ha->flags); | ||
60 | /* Reload minidump template */ | ||
61 | qla4xxx_alloc_fw_dump(ha); | ||
62 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
63 | "Firmware template reloaded\n")); | ||
64 | } | ||
65 | break; | ||
66 | case 1: | ||
67 | /* Set flag to read dump */ | ||
68 | if (test_bit(AF_82XX_FW_DUMPED, &ha->flags) && | ||
69 | !test_bit(AF_82XX_DUMP_READING, &ha->flags)) { | ||
70 | set_bit(AF_82XX_DUMP_READING, &ha->flags); | ||
71 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
72 | "Raw firmware dump ready for read on (%ld).\n", | ||
73 | ha->host_no)); | ||
74 | } | ||
75 | break; | ||
76 | case 2: | ||
77 | /* Reset HBA */ | ||
78 | qla4_8xxx_idc_lock(ha); | ||
79 | dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | ||
80 | if (dev_state == QLA82XX_DEV_READY) { | ||
81 | ql4_printk(KERN_INFO, ha, | ||
82 | "%s: Setting Need reset, reset_owner is 0x%x.\n", | ||
83 | __func__, ha->func_num); | ||
84 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, | ||
85 | QLA82XX_DEV_NEED_RESET); | ||
86 | set_bit(AF_82XX_RST_OWNER, &ha->flags); | ||
87 | } else | ||
88 | ql4_printk(KERN_INFO, ha, | ||
89 | "%s: Reset not performed as device state is 0x%x\n", | ||
90 | __func__, dev_state); | ||
91 | |||
92 | qla4_8xxx_idc_unlock(ha); | ||
93 | break; | ||
94 | default: | ||
95 | /* do nothing */ | ||
96 | break; | ||
97 | } | ||
98 | |||
99 | return count; | ||
100 | } | ||
101 | |||
102 | static struct bin_attribute sysfs_fw_dump_attr = { | ||
103 | .attr = { | ||
104 | .name = "fw_dump", | ||
105 | .mode = S_IRUSR | S_IWUSR, | ||
106 | }, | ||
107 | .size = 0, | ||
108 | .read = qla4_8xxx_sysfs_read_fw_dump, | ||
109 | .write = qla4_8xxx_sysfs_write_fw_dump, | ||
110 | }; | ||
111 | |||
112 | static struct sysfs_entry { | ||
113 | char *name; | ||
114 | struct bin_attribute *attr; | ||
115 | } bin_file_entries[] = { | ||
116 | { "fw_dump", &sysfs_fw_dump_attr }, | ||
117 | { NULL }, | ||
118 | }; | ||
119 | |||
120 | void qla4_8xxx_alloc_sysfs_attr(struct scsi_qla_host *ha) | ||
121 | { | ||
122 | struct Scsi_Host *host = ha->host; | ||
123 | struct sysfs_entry *iter; | ||
124 | int ret; | ||
125 | |||
126 | for (iter = bin_file_entries; iter->name; iter++) { | ||
127 | ret = sysfs_create_bin_file(&host->shost_gendev.kobj, | ||
128 | iter->attr); | ||
129 | if (ret) | ||
130 | ql4_printk(KERN_ERR, ha, | ||
131 | "Unable to create sysfs %s binary attribute (%d).\n", | ||
132 | iter->name, ret); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | void qla4_8xxx_free_sysfs_attr(struct scsi_qla_host *ha) | ||
137 | { | ||
138 | struct Scsi_Host *host = ha->host; | ||
139 | struct sysfs_entry *iter; | ||
140 | |||
141 | for (iter = bin_file_entries; iter->name; iter++) | ||
142 | sysfs_remove_bin_file(&host->shost_gendev.kobj, | ||
143 | iter->attr); | ||
144 | } | ||
145 | |||
12 | /* Scsi_Host attributes. */ | 146 | /* Scsi_Host attributes. */ |
13 | static ssize_t | 147 | static ssize_t |
14 | qla4xxx_fw_version_show(struct device *dev, | 148 | qla4xxx_fw_version_show(struct device *dev, |