xref: /openbmc/linux/drivers/scsi/pm8001/pm8001_ctl.c (revision 859b5d10)
1dbf9bfe6Sjack wang /*
2e5742101SSakthivel K  * PMC-Sierra 8001/8081/8088/8089 SAS/SATA based host adapters driver
3dbf9bfe6Sjack wang  *
4dbf9bfe6Sjack wang  * Copyright (c) 2008-2009 USI Co., Ltd.
5dbf9bfe6Sjack wang  * All rights reserved.
6dbf9bfe6Sjack wang  *
7dbf9bfe6Sjack wang  * Redistribution and use in source and binary forms, with or without
8dbf9bfe6Sjack wang  * modification, are permitted provided that the following conditions
9dbf9bfe6Sjack wang  * are met:
10dbf9bfe6Sjack wang  * 1. Redistributions of source code must retain the above copyright
11dbf9bfe6Sjack wang  *    notice, this list of conditions, and the following disclaimer,
12dbf9bfe6Sjack wang  *    without modification.
13dbf9bfe6Sjack wang  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14dbf9bfe6Sjack wang  *    substantially similar to the "NO WARRANTY" disclaimer below
15dbf9bfe6Sjack wang  *    ("Disclaimer") and any redistribution must be conditioned upon
16dbf9bfe6Sjack wang  *    including a substantially similar Disclaimer requirement for further
17dbf9bfe6Sjack wang  *    binary redistribution.
18dbf9bfe6Sjack wang  * 3. Neither the names of the above-listed copyright holders nor the names
19dbf9bfe6Sjack wang  *    of any contributors may be used to endorse or promote products derived
20dbf9bfe6Sjack wang  *    from this software without specific prior written permission.
21dbf9bfe6Sjack wang  *
22dbf9bfe6Sjack wang  * Alternatively, this software may be distributed under the terms of the
23dbf9bfe6Sjack wang  * GNU General Public License ("GPL") version 2 as published by the Free
24dbf9bfe6Sjack wang  * Software Foundation.
25dbf9bfe6Sjack wang  *
26dbf9bfe6Sjack wang  * NO WARRANTY
27dbf9bfe6Sjack wang  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28dbf9bfe6Sjack wang  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29dbf9bfe6Sjack wang  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
30dbf9bfe6Sjack wang  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31dbf9bfe6Sjack wang  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32dbf9bfe6Sjack wang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33dbf9bfe6Sjack wang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34dbf9bfe6Sjack wang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35dbf9bfe6Sjack wang  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
36dbf9bfe6Sjack wang  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37dbf9bfe6Sjack wang  * POSSIBILITY OF SUCH DAMAGES.
38dbf9bfe6Sjack wang  *
39dbf9bfe6Sjack wang  */
40dbf9bfe6Sjack wang #include <linux/firmware.h>
415a0e3ad6STejun Heo #include <linux/slab.h>
42dbf9bfe6Sjack wang #include "pm8001_sas.h"
43dbf9bfe6Sjack wang #include "pm8001_ctl.h"
44dbf9bfe6Sjack wang 
45dbf9bfe6Sjack wang /* scsi host attributes */
46dbf9bfe6Sjack wang 
47dbf9bfe6Sjack wang /**
48dbf9bfe6Sjack wang  * pm8001_ctl_mpi_interface_rev_show - MPI interface revision number
49dbf9bfe6Sjack wang  * @cdev: pointer to embedded class device
50dbf9bfe6Sjack wang  * @buf: the buffer returned
51dbf9bfe6Sjack wang  *
52dbf9bfe6Sjack wang  * A sysfs 'read-only' shost attribute.
53dbf9bfe6Sjack wang  */
54dbf9bfe6Sjack wang static ssize_t pm8001_ctl_mpi_interface_rev_show(struct device *cdev,
55dbf9bfe6Sjack wang 	struct device_attribute *attr, char *buf)
56dbf9bfe6Sjack wang {
57dbf9bfe6Sjack wang 	struct Scsi_Host *shost = class_to_shost(cdev);
58dbf9bfe6Sjack wang 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
59dbf9bfe6Sjack wang 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
60dbf9bfe6Sjack wang 
61e5742101SSakthivel K 	if (pm8001_ha->chip_id == chip_8001) {
62dbf9bfe6Sjack wang 		return snprintf(buf, PAGE_SIZE, "%d\n",
63e5742101SSakthivel K 			pm8001_ha->main_cfg_tbl.pm8001_tbl.interface_rev);
64e5742101SSakthivel K 	} else {
65e5742101SSakthivel K 		return snprintf(buf, PAGE_SIZE, "%d\n",
66e5742101SSakthivel K 			pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev);
67e5742101SSakthivel K 	}
68dbf9bfe6Sjack wang }
69dbf9bfe6Sjack wang static
70dbf9bfe6Sjack wang DEVICE_ATTR(interface_rev, S_IRUGO, pm8001_ctl_mpi_interface_rev_show, NULL);
71dbf9bfe6Sjack wang 
72dbf9bfe6Sjack wang /**
73dbf9bfe6Sjack wang  * pm8001_ctl_fw_version_show - firmware version
74dbf9bfe6Sjack wang  * @cdev: pointer to embedded class device
75dbf9bfe6Sjack wang  * @buf: the buffer returned
76dbf9bfe6Sjack wang  *
77dbf9bfe6Sjack wang  * A sysfs 'read-only' shost attribute.
78dbf9bfe6Sjack wang  */
79dbf9bfe6Sjack wang static ssize_t pm8001_ctl_fw_version_show(struct device *cdev,
80dbf9bfe6Sjack wang 	struct device_attribute *attr, char *buf)
81dbf9bfe6Sjack wang {
82dbf9bfe6Sjack wang 	struct Scsi_Host *shost = class_to_shost(cdev);
83dbf9bfe6Sjack wang 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
84dbf9bfe6Sjack wang 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
85dbf9bfe6Sjack wang 
86e5742101SSakthivel K 	if (pm8001_ha->chip_id == chip_8001) {
87dbf9bfe6Sjack wang 		return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
88e5742101SSakthivel K 		(u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 24),
89e5742101SSakthivel K 		(u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 16),
90e5742101SSakthivel K 		(u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 8),
91e5742101SSakthivel K 		(u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev));
92e5742101SSakthivel K 	} else {
93e5742101SSakthivel K 		return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
94e5742101SSakthivel K 		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 24),
95e5742101SSakthivel K 		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 16),
96e5742101SSakthivel K 		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 8),
97e5742101SSakthivel K 		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev));
98e5742101SSakthivel K 	}
99dbf9bfe6Sjack wang }
100dbf9bfe6Sjack wang static DEVICE_ATTR(fw_version, S_IRUGO, pm8001_ctl_fw_version_show, NULL);
101dbf9bfe6Sjack wang /**
102dbf9bfe6Sjack wang  * pm8001_ctl_max_out_io_show - max outstanding io supported
103dbf9bfe6Sjack wang  * @cdev: pointer to embedded class device
104dbf9bfe6Sjack wang  * @buf: the buffer returned
105dbf9bfe6Sjack wang  *
106dbf9bfe6Sjack wang  * A sysfs 'read-only' shost attribute.
107dbf9bfe6Sjack wang  */
108dbf9bfe6Sjack wang static ssize_t pm8001_ctl_max_out_io_show(struct device *cdev,
109dbf9bfe6Sjack wang 	struct device_attribute *attr, char *buf)
110dbf9bfe6Sjack wang {
111dbf9bfe6Sjack wang 	struct Scsi_Host *shost = class_to_shost(cdev);
112dbf9bfe6Sjack wang 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
113dbf9bfe6Sjack wang 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
114dbf9bfe6Sjack wang 
115e5742101SSakthivel K 	if (pm8001_ha->chip_id == chip_8001) {
116dbf9bfe6Sjack wang 		return snprintf(buf, PAGE_SIZE, "%d\n",
117e5742101SSakthivel K 			pm8001_ha->main_cfg_tbl.pm8001_tbl.max_out_io);
118e5742101SSakthivel K 	} else {
119e5742101SSakthivel K 		return snprintf(buf, PAGE_SIZE, "%d\n",
120e5742101SSakthivel K 			pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io);
121e5742101SSakthivel K 	}
122dbf9bfe6Sjack wang }
123dbf9bfe6Sjack wang static DEVICE_ATTR(max_out_io, S_IRUGO, pm8001_ctl_max_out_io_show, NULL);
124dbf9bfe6Sjack wang /**
125dbf9bfe6Sjack wang  * pm8001_ctl_max_devices_show - max devices support
126dbf9bfe6Sjack wang  * @cdev: pointer to embedded class device
127dbf9bfe6Sjack wang  * @buf: the buffer returned
128dbf9bfe6Sjack wang  *
129dbf9bfe6Sjack wang  * A sysfs 'read-only' shost attribute.
130dbf9bfe6Sjack wang  */
131dbf9bfe6Sjack wang static ssize_t pm8001_ctl_max_devices_show(struct device *cdev,
132dbf9bfe6Sjack wang 	struct device_attribute *attr, char *buf)
133dbf9bfe6Sjack wang {
134dbf9bfe6Sjack wang 	struct Scsi_Host *shost = class_to_shost(cdev);
135dbf9bfe6Sjack wang 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
136dbf9bfe6Sjack wang 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
137dbf9bfe6Sjack wang 
138e5742101SSakthivel K 	if (pm8001_ha->chip_id == chip_8001) {
139dbf9bfe6Sjack wang 		return snprintf(buf, PAGE_SIZE, "%04d\n",
140e5742101SSakthivel K 			(u16)(pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl >> 16)
141e5742101SSakthivel K 			);
142e5742101SSakthivel K 	} else {
143e5742101SSakthivel K 		return snprintf(buf, PAGE_SIZE, "%04d\n",
144e5742101SSakthivel K 			(u16)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl >> 16)
145e5742101SSakthivel K 			);
146e5742101SSakthivel K 	}
147dbf9bfe6Sjack wang }
148dbf9bfe6Sjack wang static DEVICE_ATTR(max_devices, S_IRUGO, pm8001_ctl_max_devices_show, NULL);
149dbf9bfe6Sjack wang /**
150dbf9bfe6Sjack wang  * pm8001_ctl_max_sg_list_show - max sg list supported iff not 0.0 for no
151dbf9bfe6Sjack wang  * hardware limitation
152dbf9bfe6Sjack wang  * @cdev: pointer to embedded class device
153dbf9bfe6Sjack wang  * @buf: the buffer returned
154dbf9bfe6Sjack wang  *
155dbf9bfe6Sjack wang  * A sysfs 'read-only' shost attribute.
156dbf9bfe6Sjack wang  */
157dbf9bfe6Sjack wang static ssize_t pm8001_ctl_max_sg_list_show(struct device *cdev,
158dbf9bfe6Sjack wang 	struct device_attribute *attr, char *buf)
159dbf9bfe6Sjack wang {
160dbf9bfe6Sjack wang 	struct Scsi_Host *shost = class_to_shost(cdev);
161dbf9bfe6Sjack wang 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
162dbf9bfe6Sjack wang 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
163dbf9bfe6Sjack wang 
164e5742101SSakthivel K 	if (pm8001_ha->chip_id == chip_8001) {
165dbf9bfe6Sjack wang 		return snprintf(buf, PAGE_SIZE, "%04d\n",
166e5742101SSakthivel K 			pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl & 0x0000FFFF
167e5742101SSakthivel K 			);
168e5742101SSakthivel K 	} else {
169e5742101SSakthivel K 		return snprintf(buf, PAGE_SIZE, "%04d\n",
170e5742101SSakthivel K 			pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl & 0x0000FFFF
171e5742101SSakthivel K 			);
172e5742101SSakthivel K 	}
173dbf9bfe6Sjack wang }
174dbf9bfe6Sjack wang static DEVICE_ATTR(max_sg_list, S_IRUGO, pm8001_ctl_max_sg_list_show, NULL);
175dbf9bfe6Sjack wang 
176dbf9bfe6Sjack wang #define SAS_1_0 0x1
177dbf9bfe6Sjack wang #define SAS_1_1 0x2
178dbf9bfe6Sjack wang #define SAS_2_0 0x4
179dbf9bfe6Sjack wang 
180dbf9bfe6Sjack wang static ssize_t
181dbf9bfe6Sjack wang show_sas_spec_support_status(unsigned int mode, char *buf)
182dbf9bfe6Sjack wang {
183dbf9bfe6Sjack wang 	ssize_t len = 0;
184dbf9bfe6Sjack wang 
185dbf9bfe6Sjack wang 	if (mode & SAS_1_1)
186dbf9bfe6Sjack wang 		len = sprintf(buf, "%s", "SAS1.1");
187dbf9bfe6Sjack wang 	if (mode & SAS_2_0)
188dbf9bfe6Sjack wang 		len += sprintf(buf + len, "%s%s", len ? ", " : "", "SAS2.0");
189dbf9bfe6Sjack wang 	len += sprintf(buf + len, "\n");
190dbf9bfe6Sjack wang 
191dbf9bfe6Sjack wang 	return len;
192dbf9bfe6Sjack wang }
193dbf9bfe6Sjack wang 
194dbf9bfe6Sjack wang /**
195dbf9bfe6Sjack wang  * pm8001_ctl_sas_spec_support_show - sas spec supported
196dbf9bfe6Sjack wang  * @cdev: pointer to embedded class device
197dbf9bfe6Sjack wang  * @buf: the buffer returned
198dbf9bfe6Sjack wang  *
199dbf9bfe6Sjack wang  * A sysfs 'read-only' shost attribute.
200dbf9bfe6Sjack wang  */
201dbf9bfe6Sjack wang static ssize_t pm8001_ctl_sas_spec_support_show(struct device *cdev,
202dbf9bfe6Sjack wang 	struct device_attribute *attr, char *buf)
203dbf9bfe6Sjack wang {
204dbf9bfe6Sjack wang 	unsigned int mode;
205dbf9bfe6Sjack wang 	struct Scsi_Host *shost = class_to_shost(cdev);
206dbf9bfe6Sjack wang 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
207dbf9bfe6Sjack wang 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
208e5742101SSakthivel K 	/* fe000000 means supports SAS2.1 */
209e5742101SSakthivel K 	if (pm8001_ha->chip_id == chip_8001)
210e5742101SSakthivel K 		mode = (pm8001_ha->main_cfg_tbl.pm8001_tbl.ctrl_cap_flag &
211e5742101SSakthivel K 							0xfe000000)>>25;
212e5742101SSakthivel K 	else
213e5742101SSakthivel K 		/* fe000000 means supports SAS2.1 */
214e5742101SSakthivel K 		mode = (pm8001_ha->main_cfg_tbl.pm80xx_tbl.ctrl_cap_flag &
215e5742101SSakthivel K 							0xfe000000)>>25;
216dbf9bfe6Sjack wang 	return show_sas_spec_support_status(mode, buf);
217dbf9bfe6Sjack wang }
218dbf9bfe6Sjack wang static DEVICE_ATTR(sas_spec_support, S_IRUGO,
219dbf9bfe6Sjack wang 		   pm8001_ctl_sas_spec_support_show, NULL);
220dbf9bfe6Sjack wang 
221dbf9bfe6Sjack wang /**
222dbf9bfe6Sjack wang  * pm8001_ctl_sas_address_show - sas address
223dbf9bfe6Sjack wang  * @cdev: pointer to embedded class device
224dbf9bfe6Sjack wang  * @buf: the buffer returned
225dbf9bfe6Sjack wang  *
226dbf9bfe6Sjack wang  * This is the controller sas address
227dbf9bfe6Sjack wang  *
228dbf9bfe6Sjack wang  * A sysfs 'read-only' shost attribute.
229dbf9bfe6Sjack wang  */
230dbf9bfe6Sjack wang static ssize_t pm8001_ctl_host_sas_address_show(struct device *cdev,
231dbf9bfe6Sjack wang 	struct device_attribute *attr, char *buf)
232dbf9bfe6Sjack wang {
233dbf9bfe6Sjack wang 	struct Scsi_Host *shost = class_to_shost(cdev);
234dbf9bfe6Sjack wang 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
235dbf9bfe6Sjack wang 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
236dbf9bfe6Sjack wang 	return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
237dbf9bfe6Sjack wang 			be64_to_cpu(*(__be64 *)pm8001_ha->sas_addr));
238dbf9bfe6Sjack wang }
239dbf9bfe6Sjack wang static DEVICE_ATTR(host_sas_address, S_IRUGO,
240dbf9bfe6Sjack wang 		   pm8001_ctl_host_sas_address_show, NULL);
241dbf9bfe6Sjack wang 
242dbf9bfe6Sjack wang /**
243dbf9bfe6Sjack wang  * pm8001_ctl_logging_level_show - logging level
244dbf9bfe6Sjack wang  * @cdev: pointer to embedded class device
245dbf9bfe6Sjack wang  * @buf: the buffer returned
246dbf9bfe6Sjack wang  *
247dbf9bfe6Sjack wang  * A sysfs 'read/write' shost attribute.
248dbf9bfe6Sjack wang  */
249dbf9bfe6Sjack wang static ssize_t pm8001_ctl_logging_level_show(struct device *cdev,
250dbf9bfe6Sjack wang 	struct device_attribute *attr, char *buf)
251dbf9bfe6Sjack wang {
252dbf9bfe6Sjack wang 	struct Scsi_Host *shost = class_to_shost(cdev);
253dbf9bfe6Sjack wang 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
254dbf9bfe6Sjack wang 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
255dbf9bfe6Sjack wang 
256dbf9bfe6Sjack wang 	return snprintf(buf, PAGE_SIZE, "%08xh\n", pm8001_ha->logging_level);
257dbf9bfe6Sjack wang }
258dbf9bfe6Sjack wang static ssize_t pm8001_ctl_logging_level_store(struct device *cdev,
259dbf9bfe6Sjack wang 	struct device_attribute *attr, const char *buf, size_t count)
260dbf9bfe6Sjack wang {
261dbf9bfe6Sjack wang 	struct Scsi_Host *shost = class_to_shost(cdev);
262dbf9bfe6Sjack wang 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
263dbf9bfe6Sjack wang 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
264dbf9bfe6Sjack wang 	int val = 0;
265dbf9bfe6Sjack wang 
266dbf9bfe6Sjack wang 	if (sscanf(buf, "%x", &val) != 1)
267dbf9bfe6Sjack wang 		return -EINVAL;
268dbf9bfe6Sjack wang 
269dbf9bfe6Sjack wang 	pm8001_ha->logging_level = val;
270dbf9bfe6Sjack wang 	return strlen(buf);
271dbf9bfe6Sjack wang }
272dbf9bfe6Sjack wang 
273dbf9bfe6Sjack wang static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR,
274dbf9bfe6Sjack wang 	pm8001_ctl_logging_level_show, pm8001_ctl_logging_level_store);
275dbf9bfe6Sjack wang /**
276dbf9bfe6Sjack wang  * pm8001_ctl_aap_log_show - aap1 event log
277dbf9bfe6Sjack wang  * @cdev: pointer to embedded class device
278dbf9bfe6Sjack wang  * @buf: the buffer returned
279dbf9bfe6Sjack wang  *
280dbf9bfe6Sjack wang  * A sysfs 'read-only' shost attribute.
281dbf9bfe6Sjack wang  */
282dbf9bfe6Sjack wang static ssize_t pm8001_ctl_aap_log_show(struct device *cdev,
283dbf9bfe6Sjack wang 	struct device_attribute *attr, char *buf)
284dbf9bfe6Sjack wang {
285dbf9bfe6Sjack wang 	struct Scsi_Host *shost = class_to_shost(cdev);
286dbf9bfe6Sjack wang 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
287dbf9bfe6Sjack wang 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
288dbf9bfe6Sjack wang 	int i;
289dbf9bfe6Sjack wang #define AAP1_MEMMAP(r, c) \
290dbf9bfe6Sjack wang 	(*(u32 *)((u8*)pm8001_ha->memoryMap.region[AAP1].virt_ptr + (r) * 32 \
291dbf9bfe6Sjack wang 	+ (c)))
292dbf9bfe6Sjack wang 
293dbf9bfe6Sjack wang 	char *str = buf;
294dbf9bfe6Sjack wang 	int max = 2;
295dbf9bfe6Sjack wang 	for (i = 0; i < max; i++) {
296dbf9bfe6Sjack wang 		str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x"
297dbf9bfe6Sjack wang 			       "0x%08x 0x%08x\n",
298dbf9bfe6Sjack wang 			       AAP1_MEMMAP(i, 0),
299dbf9bfe6Sjack wang 			       AAP1_MEMMAP(i, 4),
300dbf9bfe6Sjack wang 			       AAP1_MEMMAP(i, 8),
301dbf9bfe6Sjack wang 			       AAP1_MEMMAP(i, 12),
302dbf9bfe6Sjack wang 			       AAP1_MEMMAP(i, 16),
303dbf9bfe6Sjack wang 			       AAP1_MEMMAP(i, 20),
304dbf9bfe6Sjack wang 			       AAP1_MEMMAP(i, 24),
305dbf9bfe6Sjack wang 			       AAP1_MEMMAP(i, 28));
306dbf9bfe6Sjack wang 	}
307dbf9bfe6Sjack wang 
308dbf9bfe6Sjack wang 	return str - buf;
309dbf9bfe6Sjack wang }
310dbf9bfe6Sjack wang static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL);
311dbf9bfe6Sjack wang /**
312d078b511SAnand Kumar Santhanam  * pm8001_ctl_ib_queue_log_show - Out bound Queue log
313d078b511SAnand Kumar Santhanam  * @cdev:pointer to embedded class device
314d078b511SAnand Kumar Santhanam  * @buf: the buffer returned
315d078b511SAnand Kumar Santhanam  * A sysfs 'read-only' shost attribute.
316d078b511SAnand Kumar Santhanam  */
317d078b511SAnand Kumar Santhanam static ssize_t pm8001_ctl_ib_queue_log_show(struct device *cdev,
318d078b511SAnand Kumar Santhanam 	struct device_attribute *attr, char *buf)
319d078b511SAnand Kumar Santhanam {
320d078b511SAnand Kumar Santhanam 	struct Scsi_Host *shost = class_to_shost(cdev);
321d078b511SAnand Kumar Santhanam 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
322d078b511SAnand Kumar Santhanam 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
323d078b511SAnand Kumar Santhanam 	int offset;
324d078b511SAnand Kumar Santhanam 	char *str = buf;
325d078b511SAnand Kumar Santhanam 	int start = 0;
326d078b511SAnand Kumar Santhanam #define IB_MEMMAP(c)	\
327d078b511SAnand Kumar Santhanam 		(*(u32 *)((u8 *)pm8001_ha->	\
328d078b511SAnand Kumar Santhanam 		memoryMap.region[IB].virt_ptr +	\
329d078b511SAnand Kumar Santhanam 		pm8001_ha->evtlog_ib_offset + (c)))
330d078b511SAnand Kumar Santhanam 
331d078b511SAnand Kumar Santhanam 	for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
332d078b511SAnand Kumar Santhanam 		str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));
333d078b511SAnand Kumar Santhanam 		start = start + 4;
334d078b511SAnand Kumar Santhanam 	}
335d078b511SAnand Kumar Santhanam 	pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET;
336859b5d10SViswas G 	if (((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
337d078b511SAnand Kumar Santhanam 		pm8001_ha->evtlog_ib_offset = 0;
338d078b511SAnand Kumar Santhanam 
339d078b511SAnand Kumar Santhanam 	return str - buf;
340d078b511SAnand Kumar Santhanam }
341d078b511SAnand Kumar Santhanam 
342d078b511SAnand Kumar Santhanam static DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show, NULL);
343d078b511SAnand Kumar Santhanam /**
344d078b511SAnand Kumar Santhanam  * pm8001_ctl_ob_queue_log_show - Out bound Queue log
345d078b511SAnand Kumar Santhanam  * @cdev:pointer to embedded class device
346d078b511SAnand Kumar Santhanam  * @buf: the buffer returned
347d078b511SAnand Kumar Santhanam  * A sysfs 'read-only' shost attribute.
348d078b511SAnand Kumar Santhanam  */
349d078b511SAnand Kumar Santhanam 
350d078b511SAnand Kumar Santhanam static ssize_t pm8001_ctl_ob_queue_log_show(struct device *cdev,
351d078b511SAnand Kumar Santhanam 	struct device_attribute *attr, char *buf)
352d078b511SAnand Kumar Santhanam {
353d078b511SAnand Kumar Santhanam 	struct Scsi_Host *shost = class_to_shost(cdev);
354d078b511SAnand Kumar Santhanam 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
355d078b511SAnand Kumar Santhanam 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
356d078b511SAnand Kumar Santhanam 	int offset;
357d078b511SAnand Kumar Santhanam 	char *str = buf;
358d078b511SAnand Kumar Santhanam 	int start = 0;
359d078b511SAnand Kumar Santhanam #define OB_MEMMAP(c)	\
360d078b511SAnand Kumar Santhanam 		(*(u32 *)((u8 *)pm8001_ha->	\
361d078b511SAnand Kumar Santhanam 		memoryMap.region[OB].virt_ptr +	\
362d078b511SAnand Kumar Santhanam 		pm8001_ha->evtlog_ob_offset + (c)))
363d078b511SAnand Kumar Santhanam 
364d078b511SAnand Kumar Santhanam 	for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
365d078b511SAnand Kumar Santhanam 		str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));
366d078b511SAnand Kumar Santhanam 		start = start + 4;
367d078b511SAnand Kumar Santhanam 	}
368d078b511SAnand Kumar Santhanam 	pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET;
369859b5d10SViswas G 	if (((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
370d078b511SAnand Kumar Santhanam 		pm8001_ha->evtlog_ob_offset = 0;
371d078b511SAnand Kumar Santhanam 
372d078b511SAnand Kumar Santhanam 	return str - buf;
373d078b511SAnand Kumar Santhanam }
374d078b511SAnand Kumar Santhanam static DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show, NULL);
375d078b511SAnand Kumar Santhanam /**
376966fdcffSAnand Kumar Santhanam  * pm8001_ctl_bios_version_show - Bios version Display
377966fdcffSAnand Kumar Santhanam  * @cdev:pointer to embedded class device
378966fdcffSAnand Kumar Santhanam  * @buf:the buffer returned
379966fdcffSAnand Kumar Santhanam  * A sysfs 'read-only' shost attribute.
380966fdcffSAnand Kumar Santhanam  */
381966fdcffSAnand Kumar Santhanam static ssize_t pm8001_ctl_bios_version_show(struct device *cdev,
382966fdcffSAnand Kumar Santhanam 	struct device_attribute *attr, char *buf)
383966fdcffSAnand Kumar Santhanam {
384966fdcffSAnand Kumar Santhanam 	struct Scsi_Host *shost = class_to_shost(cdev);
385966fdcffSAnand Kumar Santhanam 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
386966fdcffSAnand Kumar Santhanam 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
387966fdcffSAnand Kumar Santhanam 	char *str = buf;
388966fdcffSAnand Kumar Santhanam 	void *virt_addr;
389966fdcffSAnand Kumar Santhanam 	int bios_index;
390966fdcffSAnand Kumar Santhanam 	DECLARE_COMPLETION_ONSTACK(completion);
391966fdcffSAnand Kumar Santhanam 	struct pm8001_ioctl_payload payload;
392966fdcffSAnand Kumar Santhanam 
393966fdcffSAnand Kumar Santhanam 	pm8001_ha->nvmd_completion = &completion;
394966fdcffSAnand Kumar Santhanam 	payload.minor_function = 7;
395966fdcffSAnand Kumar Santhanam 	payload.offset = 0;
396966fdcffSAnand Kumar Santhanam 	payload.length = 4096;
397966fdcffSAnand Kumar Santhanam 	payload.func_specific = kzalloc(4096, GFP_KERNEL);
398966fdcffSAnand Kumar Santhanam 	PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload);
399966fdcffSAnand Kumar Santhanam 	wait_for_completion(&completion);
400966fdcffSAnand Kumar Santhanam 	virt_addr = pm8001_ha->memoryMap.region[NVMD].virt_ptr;
401966fdcffSAnand Kumar Santhanam 	for (bios_index = BIOSOFFSET; bios_index < BIOS_OFFSET_LIMIT;
402966fdcffSAnand Kumar Santhanam 		bios_index++)
403966fdcffSAnand Kumar Santhanam 		str += sprintf(str, "%c",
404966fdcffSAnand Kumar Santhanam 			*((u8 *)((u8 *)virt_addr+bios_index)));
405966fdcffSAnand Kumar Santhanam 	return str - buf;
406966fdcffSAnand Kumar Santhanam }
407966fdcffSAnand Kumar Santhanam static DEVICE_ATTR(bios_version, S_IRUGO, pm8001_ctl_bios_version_show, NULL);
408966fdcffSAnand Kumar Santhanam /**
409dbf9bfe6Sjack wang  * pm8001_ctl_aap_log_show - IOP event log
410dbf9bfe6Sjack wang  * @cdev: pointer to embedded class device
411dbf9bfe6Sjack wang  * @buf: the buffer returned
412dbf9bfe6Sjack wang  *
413dbf9bfe6Sjack wang  * A sysfs 'read-only' shost attribute.
414dbf9bfe6Sjack wang  */
415dbf9bfe6Sjack wang static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,
416dbf9bfe6Sjack wang 	struct device_attribute *attr, char *buf)
417dbf9bfe6Sjack wang {
418dbf9bfe6Sjack wang 	struct Scsi_Host *shost = class_to_shost(cdev);
419dbf9bfe6Sjack wang 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
420dbf9bfe6Sjack wang 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
421dbf9bfe6Sjack wang #define IOP_MEMMAP(r, c) \
422dbf9bfe6Sjack wang 	(*(u32 *)((u8*)pm8001_ha->memoryMap.region[IOP].virt_ptr + (r) * 32 \
423dbf9bfe6Sjack wang 	+ (c)))
424dbf9bfe6Sjack wang 	int i;
425dbf9bfe6Sjack wang 	char *str = buf;
426dbf9bfe6Sjack wang 	int max = 2;
427dbf9bfe6Sjack wang 	for (i = 0; i < max; i++) {
428dbf9bfe6Sjack wang 		str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x"
429dbf9bfe6Sjack wang 			       "0x%08x 0x%08x\n",
430dbf9bfe6Sjack wang 			       IOP_MEMMAP(i, 0),
431dbf9bfe6Sjack wang 			       IOP_MEMMAP(i, 4),
432dbf9bfe6Sjack wang 			       IOP_MEMMAP(i, 8),
433dbf9bfe6Sjack wang 			       IOP_MEMMAP(i, 12),
434dbf9bfe6Sjack wang 			       IOP_MEMMAP(i, 16),
435dbf9bfe6Sjack wang 			       IOP_MEMMAP(i, 20),
436dbf9bfe6Sjack wang 			       IOP_MEMMAP(i, 24),
437dbf9bfe6Sjack wang 			       IOP_MEMMAP(i, 28));
438dbf9bfe6Sjack wang 	}
439dbf9bfe6Sjack wang 
440dbf9bfe6Sjack wang 	return str - buf;
441dbf9bfe6Sjack wang }
442dbf9bfe6Sjack wang static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
443dbf9bfe6Sjack wang 
444d078b511SAnand Kumar Santhanam /**
445d078b511SAnand Kumar Santhanam  ** pm8001_ctl_fatal_log_show - fatal error logging
446d078b511SAnand Kumar Santhanam  ** @cdev:pointer to embedded class device
447d078b511SAnand Kumar Santhanam  ** @buf: the buffer returned
448d078b511SAnand Kumar Santhanam  **
449d078b511SAnand Kumar Santhanam  ** A sysfs 'read-only' shost attribute.
450d078b511SAnand Kumar Santhanam  **/
451d078b511SAnand Kumar Santhanam 
452d078b511SAnand Kumar Santhanam static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,
453d078b511SAnand Kumar Santhanam 	struct device_attribute *attr, char *buf)
454d078b511SAnand Kumar Santhanam {
455d078b511SAnand Kumar Santhanam 	u32 count;
456d078b511SAnand Kumar Santhanam 
457d078b511SAnand Kumar Santhanam 	count = pm80xx_get_fatal_dump(cdev, attr, buf);
458d078b511SAnand Kumar Santhanam 	return count;
459d078b511SAnand Kumar Santhanam }
460d078b511SAnand Kumar Santhanam 
461d078b511SAnand Kumar Santhanam static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL);
462d078b511SAnand Kumar Santhanam 
463d078b511SAnand Kumar Santhanam 
464d078b511SAnand Kumar Santhanam /**
465d078b511SAnand Kumar Santhanam  ** pm8001_ctl_gsm_log_show - gsm dump collection
466d078b511SAnand Kumar Santhanam  ** @cdev:pointer to embedded class device
467d078b511SAnand Kumar Santhanam  ** @buf: the buffer returned
468d078b511SAnand Kumar Santhanam  **A sysfs 'read-only' shost attribute.
469d078b511SAnand Kumar Santhanam  **/
470d078b511SAnand Kumar Santhanam static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev,
471d078b511SAnand Kumar Santhanam 	struct device_attribute *attr, char *buf)
472d078b511SAnand Kumar Santhanam {
473d078b511SAnand Kumar Santhanam 	u32 count;
474d078b511SAnand Kumar Santhanam 
475d078b511SAnand Kumar Santhanam 	count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf);
476d078b511SAnand Kumar Santhanam 	return count;
477d078b511SAnand Kumar Santhanam }
478d078b511SAnand Kumar Santhanam 
479d078b511SAnand Kumar Santhanam static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL);
480d078b511SAnand Kumar Santhanam 
481dbf9bfe6Sjack wang #define FLASH_CMD_NONE      0x00
482dbf9bfe6Sjack wang #define FLASH_CMD_UPDATE    0x01
483dbf9bfe6Sjack wang #define FLASH_CMD_SET_NVMD    0x02
484dbf9bfe6Sjack wang 
485dbf9bfe6Sjack wang struct flash_command {
486dbf9bfe6Sjack wang      u8      command[8];
487dbf9bfe6Sjack wang      int     code;
488dbf9bfe6Sjack wang };
489dbf9bfe6Sjack wang 
490dbf9bfe6Sjack wang static struct flash_command flash_command_table[] =
491dbf9bfe6Sjack wang {
492dbf9bfe6Sjack wang      {"set_nvmd",    FLASH_CMD_SET_NVMD},
493dbf9bfe6Sjack wang      {"update",      FLASH_CMD_UPDATE},
494dbf9bfe6Sjack wang      {"",            FLASH_CMD_NONE} /* Last entry should be NULL. */
495dbf9bfe6Sjack wang };
496dbf9bfe6Sjack wang 
497dbf9bfe6Sjack wang struct error_fw {
498dbf9bfe6Sjack wang      char    *reason;
499dbf9bfe6Sjack wang      int     err_code;
500dbf9bfe6Sjack wang };
501dbf9bfe6Sjack wang 
502dbf9bfe6Sjack wang static struct error_fw flash_error_table[] =
503dbf9bfe6Sjack wang {
504dbf9bfe6Sjack wang      {"Failed to open fw image file",	FAIL_OPEN_BIOS_FILE},
505dbf9bfe6Sjack wang      {"image header mismatch",		FLASH_UPDATE_HDR_ERR},
506dbf9bfe6Sjack wang      {"image offset mismatch",		FLASH_UPDATE_OFFSET_ERR},
507dbf9bfe6Sjack wang      {"image CRC Error",		FLASH_UPDATE_CRC_ERR},
508dbf9bfe6Sjack wang      {"image length Error.",		FLASH_UPDATE_LENGTH_ERR},
509dbf9bfe6Sjack wang      {"Failed to program flash chip",	FLASH_UPDATE_HW_ERR},
510dbf9bfe6Sjack wang      {"Flash chip not supported.",	FLASH_UPDATE_DNLD_NOT_SUPPORTED},
511dbf9bfe6Sjack wang      {"Flash update disabled.",		FLASH_UPDATE_DISABLED},
512dbf9bfe6Sjack wang      {"Flash in progress",		FLASH_IN_PROGRESS},
513dbf9bfe6Sjack wang      {"Image file size Error",		FAIL_FILE_SIZE},
514dbf9bfe6Sjack wang      {"Input parameter error",		FAIL_PARAMETERS},
515dbf9bfe6Sjack wang      {"Out of memory",			FAIL_OUT_MEMORY},
516dbf9bfe6Sjack wang      {"OK", 0}	/* Last entry err_code = 0. */
517dbf9bfe6Sjack wang };
518dbf9bfe6Sjack wang 
519dbf9bfe6Sjack wang static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)
520dbf9bfe6Sjack wang {
521dbf9bfe6Sjack wang 	struct pm8001_ioctl_payload	*payload;
522dbf9bfe6Sjack wang 	DECLARE_COMPLETION_ONSTACK(completion);
523dbf9bfe6Sjack wang 	u8		*ioctlbuffer = NULL;
524dbf9bfe6Sjack wang 	u32		length = 0;
525dbf9bfe6Sjack wang 	u32		ret = 0;
526dbf9bfe6Sjack wang 
527dbf9bfe6Sjack wang 	length = 1024 * 5 + sizeof(*payload) - 1;
528dbf9bfe6Sjack wang 	ioctlbuffer = kzalloc(length, GFP_KERNEL);
529dbf9bfe6Sjack wang 	if (!ioctlbuffer)
530dbf9bfe6Sjack wang 		return -ENOMEM;
531dbf9bfe6Sjack wang 	if ((pm8001_ha->fw_image->size <= 0) ||
532dbf9bfe6Sjack wang 	    (pm8001_ha->fw_image->size > 4096)) {
533dbf9bfe6Sjack wang 		ret = FAIL_FILE_SIZE;
534dbf9bfe6Sjack wang 		goto out;
535dbf9bfe6Sjack wang 	}
536dbf9bfe6Sjack wang 	payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
5371c75a679SSakthivel K 	memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data,
538dbf9bfe6Sjack wang 				pm8001_ha->fw_image->size);
539dbf9bfe6Sjack wang 	payload->length = pm8001_ha->fw_image->size;
540dbf9bfe6Sjack wang 	payload->id = 0;
5411c75a679SSakthivel K 	payload->minor_function = 0x1;
542dbf9bfe6Sjack wang 	pm8001_ha->nvmd_completion = &completion;
543dbf9bfe6Sjack wang 	ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload);
544dbf9bfe6Sjack wang 	wait_for_completion(&completion);
545dbf9bfe6Sjack wang out:
546dbf9bfe6Sjack wang 	kfree(ioctlbuffer);
547dbf9bfe6Sjack wang 	return ret;
548dbf9bfe6Sjack wang }
549dbf9bfe6Sjack wang 
550dbf9bfe6Sjack wang static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)
551dbf9bfe6Sjack wang {
552dbf9bfe6Sjack wang 	struct pm8001_ioctl_payload	*payload;
553dbf9bfe6Sjack wang 	DECLARE_COMPLETION_ONSTACK(completion);
554dbf9bfe6Sjack wang 	u8		*ioctlbuffer = NULL;
555dbf9bfe6Sjack wang 	u32		length = 0;
556dbf9bfe6Sjack wang 	struct fw_control_info	*fwControl;
557dbf9bfe6Sjack wang 	u32		loopNumber, loopcount = 0;
558dbf9bfe6Sjack wang 	u32		sizeRead = 0;
559dbf9bfe6Sjack wang 	u32		partitionSize, partitionSizeTmp;
560dbf9bfe6Sjack wang 	u32		ret = 0;
561dbf9bfe6Sjack wang 	u32		partitionNumber = 0;
562dbf9bfe6Sjack wang 	struct pm8001_fw_image_header *image_hdr;
563dbf9bfe6Sjack wang 
564dbf9bfe6Sjack wang 	length = 1024 * 16 + sizeof(*payload) - 1;
565dbf9bfe6Sjack wang 	ioctlbuffer = kzalloc(length, GFP_KERNEL);
566dbf9bfe6Sjack wang 	image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data;
567dbf9bfe6Sjack wang 	if (!ioctlbuffer)
568dbf9bfe6Sjack wang 		return -ENOMEM;
569dbf9bfe6Sjack wang 	if (pm8001_ha->fw_image->size < 28) {
570dbf9bfe6Sjack wang 		ret = FAIL_FILE_SIZE;
571dbf9bfe6Sjack wang 		goto out;
572dbf9bfe6Sjack wang 	}
573dbf9bfe6Sjack wang 
574dbf9bfe6Sjack wang 	while (sizeRead < pm8001_ha->fw_image->size) {
575dbf9bfe6Sjack wang 		partitionSizeTmp =
576dbf9bfe6Sjack wang 			*(u32 *)((u8 *)&image_hdr->image_length + sizeRead);
577dbf9bfe6Sjack wang 		partitionSize = be32_to_cpu(partitionSizeTmp);
578dbf9bfe6Sjack wang 		loopcount = (partitionSize + HEADER_LEN)/IOCTL_BUF_SIZE;
579dbf9bfe6Sjack wang 		if (loopcount % IOCTL_BUF_SIZE)
580dbf9bfe6Sjack wang 			loopcount++;
581dbf9bfe6Sjack wang 		if (loopcount == 0)
582dbf9bfe6Sjack wang 			loopcount++;
583dbf9bfe6Sjack wang 		for (loopNumber = 0; loopNumber < loopcount; loopNumber++) {
584dbf9bfe6Sjack wang 			payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
585dbf9bfe6Sjack wang 			payload->length = 1024*16;
586dbf9bfe6Sjack wang 			payload->id = 0;
587dbf9bfe6Sjack wang 			fwControl =
5881c75a679SSakthivel K 			      (struct fw_control_info *)&payload->func_specific;
589dbf9bfe6Sjack wang 			fwControl->len = IOCTL_BUF_SIZE;   /* IN */
590dbf9bfe6Sjack wang 			fwControl->size = partitionSize + HEADER_LEN;/* IN */
591dbf9bfe6Sjack wang 			fwControl->retcode = 0;/* OUT */
592dbf9bfe6Sjack wang 			fwControl->offset = loopNumber * IOCTL_BUF_SIZE;/*OUT */
593dbf9bfe6Sjack wang 
594dbf9bfe6Sjack wang 		/* for the last chunk of data in case file size is not even with
595dbf9bfe6Sjack wang 		4k, load only the rest*/
596dbf9bfe6Sjack wang 		if (((loopcount-loopNumber) == 1) &&
597dbf9bfe6Sjack wang 			((partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE)) {
598dbf9bfe6Sjack wang 			fwControl->len =
599dbf9bfe6Sjack wang 				(partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE;
600dbf9bfe6Sjack wang 			memcpy((u8 *)fwControl->buffer,
601dbf9bfe6Sjack wang 				(u8 *)pm8001_ha->fw_image->data + sizeRead,
602dbf9bfe6Sjack wang 				(partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE);
603dbf9bfe6Sjack wang 			sizeRead +=
604dbf9bfe6Sjack wang 				(partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE;
605dbf9bfe6Sjack wang 		} else {
606dbf9bfe6Sjack wang 			memcpy((u8 *)fwControl->buffer,
607dbf9bfe6Sjack wang 				(u8 *)pm8001_ha->fw_image->data + sizeRead,
608dbf9bfe6Sjack wang 				IOCTL_BUF_SIZE);
609dbf9bfe6Sjack wang 			sizeRead += IOCTL_BUF_SIZE;
610dbf9bfe6Sjack wang 		}
611dbf9bfe6Sjack wang 
612dbf9bfe6Sjack wang 		pm8001_ha->nvmd_completion = &completion;
613dbf9bfe6Sjack wang 		ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload);
614dbf9bfe6Sjack wang 		wait_for_completion(&completion);
615dbf9bfe6Sjack wang 		if (ret || (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS)) {
616dbf9bfe6Sjack wang 			ret = fwControl->retcode;
617dbf9bfe6Sjack wang 			kfree(ioctlbuffer);
618dbf9bfe6Sjack wang 			ioctlbuffer = NULL;
619dbf9bfe6Sjack wang 			break;
620dbf9bfe6Sjack wang 		}
621dbf9bfe6Sjack wang 	}
622dbf9bfe6Sjack wang 	if (ret)
623dbf9bfe6Sjack wang 		break;
624dbf9bfe6Sjack wang 	partitionNumber++;
625dbf9bfe6Sjack wang }
626dbf9bfe6Sjack wang out:
627dbf9bfe6Sjack wang 	kfree(ioctlbuffer);
628dbf9bfe6Sjack wang 	return ret;
629dbf9bfe6Sjack wang }
630dbf9bfe6Sjack wang static ssize_t pm8001_store_update_fw(struct device *cdev,
631dbf9bfe6Sjack wang 				      struct device_attribute *attr,
632dbf9bfe6Sjack wang 				      const char *buf, size_t count)
633dbf9bfe6Sjack wang {
634dbf9bfe6Sjack wang 	struct Scsi_Host *shost = class_to_shost(cdev);
635dbf9bfe6Sjack wang 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
636dbf9bfe6Sjack wang 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
637dbf9bfe6Sjack wang 	char *cmd_ptr, *filename_ptr;
638dbf9bfe6Sjack wang 	int res, i;
639dbf9bfe6Sjack wang 	int flash_command = FLASH_CMD_NONE;
640dbf9bfe6Sjack wang 	int err = 0;
641dbf9bfe6Sjack wang 	if (!capable(CAP_SYS_ADMIN))
642dbf9bfe6Sjack wang 		return -EACCES;
643dbf9bfe6Sjack wang 
644dbf9bfe6Sjack wang 	cmd_ptr = kzalloc(count*2, GFP_KERNEL);
645dbf9bfe6Sjack wang 
646dbf9bfe6Sjack wang 	if (!cmd_ptr) {
647dbf9bfe6Sjack wang 		err = FAIL_OUT_MEMORY;
648dbf9bfe6Sjack wang 		goto out;
649dbf9bfe6Sjack wang 	}
650dbf9bfe6Sjack wang 
651dbf9bfe6Sjack wang 	filename_ptr = cmd_ptr + count;
652dbf9bfe6Sjack wang 	res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
653dbf9bfe6Sjack wang 	if (res != 2) {
654dbf9bfe6Sjack wang 		err = FAIL_PARAMETERS;
655dbf9bfe6Sjack wang 		goto out1;
656dbf9bfe6Sjack wang 	}
657dbf9bfe6Sjack wang 
658dbf9bfe6Sjack wang 	for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
659dbf9bfe6Sjack wang 		if (!memcmp(flash_command_table[i].command,
660dbf9bfe6Sjack wang 				 cmd_ptr, strlen(cmd_ptr))) {
661dbf9bfe6Sjack wang 			flash_command = flash_command_table[i].code;
662dbf9bfe6Sjack wang 			break;
663dbf9bfe6Sjack wang 		}
664dbf9bfe6Sjack wang 	}
665dbf9bfe6Sjack wang 	if (flash_command == FLASH_CMD_NONE) {
666dbf9bfe6Sjack wang 		err = FAIL_PARAMETERS;
667dbf9bfe6Sjack wang 		goto out1;
668dbf9bfe6Sjack wang 	}
669dbf9bfe6Sjack wang 
670dbf9bfe6Sjack wang 	if (pm8001_ha->fw_status == FLASH_IN_PROGRESS) {
671dbf9bfe6Sjack wang 		err = FLASH_IN_PROGRESS;
672dbf9bfe6Sjack wang 		goto out1;
673dbf9bfe6Sjack wang 	}
674dbf9bfe6Sjack wang 	err = request_firmware(&pm8001_ha->fw_image,
675dbf9bfe6Sjack wang 			       filename_ptr,
676dbf9bfe6Sjack wang 			       pm8001_ha->dev);
677dbf9bfe6Sjack wang 
678dbf9bfe6Sjack wang 	if (err) {
679dbf9bfe6Sjack wang 		PM8001_FAIL_DBG(pm8001_ha,
680dbf9bfe6Sjack wang 			pm8001_printk("Failed to load firmware image file %s,"
681dbf9bfe6Sjack wang 			" error %d\n", filename_ptr, err));
682dbf9bfe6Sjack wang 		err = FAIL_OPEN_BIOS_FILE;
683dbf9bfe6Sjack wang 		goto out1;
684dbf9bfe6Sjack wang 	}
685dbf9bfe6Sjack wang 
686dbf9bfe6Sjack wang 	switch (flash_command) {
687dbf9bfe6Sjack wang 	case FLASH_CMD_UPDATE:
688dbf9bfe6Sjack wang 		pm8001_ha->fw_status = FLASH_IN_PROGRESS;
689dbf9bfe6Sjack wang 		err = pm8001_update_flash(pm8001_ha);
690dbf9bfe6Sjack wang 		break;
691dbf9bfe6Sjack wang 	case FLASH_CMD_SET_NVMD:
692dbf9bfe6Sjack wang 		pm8001_ha->fw_status = FLASH_IN_PROGRESS;
693dbf9bfe6Sjack wang 		err = pm8001_set_nvmd(pm8001_ha);
694dbf9bfe6Sjack wang 		break;
695dbf9bfe6Sjack wang 	default:
696dbf9bfe6Sjack wang 		pm8001_ha->fw_status = FAIL_PARAMETERS;
697dbf9bfe6Sjack wang 		err = FAIL_PARAMETERS;
698dbf9bfe6Sjack wang 		break;
699dbf9bfe6Sjack wang 	}
700dbf9bfe6Sjack wang 	release_firmware(pm8001_ha->fw_image);
701dbf9bfe6Sjack wang out1:
702dbf9bfe6Sjack wang 	kfree(cmd_ptr);
703dbf9bfe6Sjack wang out:
704dbf9bfe6Sjack wang 	pm8001_ha->fw_status = err;
705dbf9bfe6Sjack wang 
706dbf9bfe6Sjack wang 	if (!err)
707dbf9bfe6Sjack wang 		return count;
708dbf9bfe6Sjack wang 	else
709dbf9bfe6Sjack wang 		return -err;
710dbf9bfe6Sjack wang }
711dbf9bfe6Sjack wang 
712dbf9bfe6Sjack wang static ssize_t pm8001_show_update_fw(struct device *cdev,
713dbf9bfe6Sjack wang 				     struct device_attribute *attr, char *buf)
714dbf9bfe6Sjack wang {
715dbf9bfe6Sjack wang 	int i;
716dbf9bfe6Sjack wang 	struct Scsi_Host *shost = class_to_shost(cdev);
717dbf9bfe6Sjack wang 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
718dbf9bfe6Sjack wang 	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
719dbf9bfe6Sjack wang 
720dbf9bfe6Sjack wang 	for (i = 0; flash_error_table[i].err_code != 0; i++) {
721dbf9bfe6Sjack wang 		if (flash_error_table[i].err_code == pm8001_ha->fw_status)
722dbf9bfe6Sjack wang 			break;
723dbf9bfe6Sjack wang 	}
724dbf9bfe6Sjack wang 	if (pm8001_ha->fw_status != FLASH_IN_PROGRESS)
725dbf9bfe6Sjack wang 		pm8001_ha->fw_status = FLASH_OK;
726dbf9bfe6Sjack wang 
727dbf9bfe6Sjack wang 	return snprintf(buf, PAGE_SIZE, "status=%x %s\n",
728dbf9bfe6Sjack wang 			flash_error_table[i].err_code,
729dbf9bfe6Sjack wang 			flash_error_table[i].reason);
730dbf9bfe6Sjack wang }
731dbf9bfe6Sjack wang 
732dbf9bfe6Sjack wang static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUGO,
733dbf9bfe6Sjack wang 	pm8001_show_update_fw, pm8001_store_update_fw);
734dbf9bfe6Sjack wang struct device_attribute *pm8001_host_attrs[] = {
735dbf9bfe6Sjack wang 	&dev_attr_interface_rev,
736dbf9bfe6Sjack wang 	&dev_attr_fw_version,
737dbf9bfe6Sjack wang 	&dev_attr_update_fw,
738dbf9bfe6Sjack wang 	&dev_attr_aap_log,
739dbf9bfe6Sjack wang 	&dev_attr_iop_log,
740d078b511SAnand Kumar Santhanam 	&dev_attr_fatal_log,
741d078b511SAnand Kumar Santhanam 	&dev_attr_gsm_log,
742dbf9bfe6Sjack wang 	&dev_attr_max_out_io,
743dbf9bfe6Sjack wang 	&dev_attr_max_devices,
744dbf9bfe6Sjack wang 	&dev_attr_max_sg_list,
745dbf9bfe6Sjack wang 	&dev_attr_sas_spec_support,
746dbf9bfe6Sjack wang 	&dev_attr_logging_level,
747dbf9bfe6Sjack wang 	&dev_attr_host_sas_address,
748966fdcffSAnand Kumar Santhanam 	&dev_attr_bios_version,
749d078b511SAnand Kumar Santhanam 	&dev_attr_ib_log,
750d078b511SAnand Kumar Santhanam 	&dev_attr_ob_log,
751dbf9bfe6Sjack wang 	NULL,
752dbf9bfe6Sjack wang };
753dbf9bfe6Sjack wang 
754