2 *******************************************************************************
4 ** FILE NAME : arcmsr_attr.c
6 ** Description: attributes exported to sysfs and device host
7 *******************************************************************************
8 ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
10 ** Web site: www.areca.com.tw
11 ** E-mail: support@areca.com.tw
13 ** This program is free software; you can redistribute it and/or modify
14 ** it under the terms of the GNU General Public License version 2 as
15 ** published by the Free Software Foundation.
16 ** This program is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ** GNU General Public License for more details.
20 *******************************************************************************
21 ** Redistribution and use in source and binary forms, with or without
22 ** modification, are permitted provided that the following conditions
24 ** 1. Redistributions of source code must retain the above copyright
25 ** notice, this list of conditions and the following disclaimer.
26 ** 2. Redistributions in binary form must reproduce the above copyright
27 ** notice, this list of conditions and the following disclaimer in the
28 ** documentation and/or other materials provided with the distribution.
29 ** 3. The name of the author may not be used to endorse or promote products
30 ** derived from this software without specific prior written permission.
32 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
33 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
35 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
36 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT
37 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
38 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
39 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 ** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF
41 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 *******************************************************************************
43 ** For history of changes, see Documentation/scsi/ChangeLog.arcmsr
44 ** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt
45 *******************************************************************************
47 #include <linux/module.h>
48 #include <linux/kernel.h>
49 #include <linux/init.h>
50 #include <linux/errno.h>
51 #include <linux/delay.h>
52 #include <linux/pci.h>
53 #include <linux/circ_buf.h>
55 #include <scsi/scsi_cmnd.h>
56 #include <scsi/scsi_device.h>
57 #include <scsi/scsi_host.h>
58 #include <scsi/scsi_transport.h>
61 struct device_attribute
*arcmsr_host_attrs
[];
63 static ssize_t
arcmsr_sysfs_iop_message_read(struct file
*filp
,
65 struct bin_attribute
*bin
,
66 char *buf
, loff_t off
,
69 struct device
*dev
= container_of(kobj
,struct device
,kobj
);
70 struct Scsi_Host
*host
= class_to_shost(dev
);
71 struct AdapterControlBlock
*acb
= (struct AdapterControlBlock
*) host
->hostdata
;
73 int32_t allxfer_len
= 0;
76 if (!capable(CAP_SYS_ADMIN
))
79 /* do message unit read. */
80 ptmpQbuffer
= (uint8_t *)buf
;
81 spin_lock_irqsave(&acb
->rqbuffer_lock
, flags
);
82 if (acb
->rqbuf_getIndex
!= acb
->rqbuf_putIndex
) {
83 unsigned int tail
= acb
->rqbuf_getIndex
;
84 unsigned int head
= acb
->rqbuf_putIndex
;
85 unsigned int cnt_to_end
= CIRC_CNT_TO_END(head
, tail
, ARCMSR_MAX_QBUFFER
);
87 allxfer_len
= CIRC_CNT(head
, tail
, ARCMSR_MAX_QBUFFER
);
88 if (allxfer_len
> ARCMSR_API_DATA_BUFLEN
)
89 allxfer_len
= ARCMSR_API_DATA_BUFLEN
;
91 if (allxfer_len
<= cnt_to_end
)
92 memcpy(ptmpQbuffer
, acb
->rqbuffer
+ tail
, allxfer_len
);
94 memcpy(ptmpQbuffer
, acb
->rqbuffer
+ tail
, cnt_to_end
);
95 memcpy(ptmpQbuffer
+ cnt_to_end
, acb
->rqbuffer
, allxfer_len
- cnt_to_end
);
97 acb
->rqbuf_getIndex
= (acb
->rqbuf_getIndex
+ allxfer_len
) % ARCMSR_MAX_QBUFFER
;
99 if (acb
->acb_flags
& ACB_F_IOPDATA_OVERFLOW
) {
100 struct QBUFFER __iomem
*prbuffer
;
101 acb
->acb_flags
&= ~ACB_F_IOPDATA_OVERFLOW
;
102 prbuffer
= arcmsr_get_iop_rqbuffer(acb
);
103 if (arcmsr_Read_iop_rqbuffer_data(acb
, prbuffer
) == 0)
104 acb
->acb_flags
|= ACB_F_IOPDATA_OVERFLOW
;
106 spin_unlock_irqrestore(&acb
->rqbuffer_lock
, flags
);
110 static ssize_t
arcmsr_sysfs_iop_message_write(struct file
*filp
,
111 struct kobject
*kobj
,
112 struct bin_attribute
*bin
,
113 char *buf
, loff_t off
,
116 struct device
*dev
= container_of(kobj
,struct device
,kobj
);
117 struct Scsi_Host
*host
= class_to_shost(dev
);
118 struct AdapterControlBlock
*acb
= (struct AdapterControlBlock
*) host
->hostdata
;
119 int32_t user_len
, cnt2end
;
120 uint8_t *pQbuffer
, *ptmpuserbuffer
;
123 if (!capable(CAP_SYS_ADMIN
))
125 if (count
> ARCMSR_API_DATA_BUFLEN
)
127 /* do message unit write. */
128 ptmpuserbuffer
= (uint8_t *)buf
;
129 user_len
= (int32_t)count
;
130 spin_lock_irqsave(&acb
->wqbuffer_lock
, flags
);
131 if (acb
->wqbuf_putIndex
!= acb
->wqbuf_getIndex
) {
132 arcmsr_write_ioctldata2iop(acb
);
133 spin_unlock_irqrestore(&acb
->wqbuffer_lock
, flags
);
134 return 0; /*need retry*/
136 pQbuffer
= &acb
->wqbuffer
[acb
->wqbuf_putIndex
];
137 cnt2end
= ARCMSR_MAX_QBUFFER
- acb
->wqbuf_putIndex
;
138 if (user_len
> cnt2end
) {
139 memcpy(pQbuffer
, ptmpuserbuffer
, cnt2end
);
140 ptmpuserbuffer
+= cnt2end
;
142 acb
->wqbuf_putIndex
= 0;
143 pQbuffer
= acb
->wqbuffer
;
145 memcpy(pQbuffer
, ptmpuserbuffer
, user_len
);
146 acb
->wqbuf_putIndex
+= user_len
;
147 acb
->wqbuf_putIndex
%= ARCMSR_MAX_QBUFFER
;
148 if (acb
->acb_flags
& ACB_F_MESSAGE_WQBUFFER_CLEARED
) {
150 ~ACB_F_MESSAGE_WQBUFFER_CLEARED
;
151 arcmsr_write_ioctldata2iop(acb
);
153 spin_unlock_irqrestore(&acb
->wqbuffer_lock
, flags
);
158 static ssize_t
arcmsr_sysfs_iop_message_clear(struct file
*filp
,
159 struct kobject
*kobj
,
160 struct bin_attribute
*bin
,
161 char *buf
, loff_t off
,
164 struct device
*dev
= container_of(kobj
,struct device
,kobj
);
165 struct Scsi_Host
*host
= class_to_shost(dev
);
166 struct AdapterControlBlock
*acb
= (struct AdapterControlBlock
*) host
->hostdata
;
170 if (!capable(CAP_SYS_ADMIN
))
173 arcmsr_clear_iop2drv_rqueue_buffer(acb
);
175 (ACB_F_MESSAGE_WQBUFFER_CLEARED
176 | ACB_F_MESSAGE_RQBUFFER_CLEARED
177 | ACB_F_MESSAGE_WQBUFFER_READED
);
178 spin_lock_irqsave(&acb
->rqbuffer_lock
, flags
);
179 acb
->rqbuf_getIndex
= 0;
180 acb
->rqbuf_putIndex
= 0;
181 spin_unlock_irqrestore(&acb
->rqbuffer_lock
, flags
);
182 spin_lock_irqsave(&acb
->wqbuffer_lock
, flags
);
183 acb
->wqbuf_getIndex
= 0;
184 acb
->wqbuf_putIndex
= 0;
185 spin_unlock_irqrestore(&acb
->wqbuffer_lock
, flags
);
186 pQbuffer
= acb
->rqbuffer
;
187 memset(pQbuffer
, 0, sizeof (struct QBUFFER
));
188 pQbuffer
= acb
->wqbuffer
;
189 memset(pQbuffer
, 0, sizeof (struct QBUFFER
));
193 static const struct bin_attribute arcmsr_sysfs_message_read_attr
= {
198 .size
= ARCMSR_API_DATA_BUFLEN
,
199 .read
= arcmsr_sysfs_iop_message_read
,
202 static const struct bin_attribute arcmsr_sysfs_message_write_attr
= {
207 .size
= ARCMSR_API_DATA_BUFLEN
,
208 .write
= arcmsr_sysfs_iop_message_write
,
211 static const struct bin_attribute arcmsr_sysfs_message_clear_attr
= {
217 .write
= arcmsr_sysfs_iop_message_clear
,
220 int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock
*acb
)
222 struct Scsi_Host
*host
= acb
->host
;
225 error
= sysfs_create_bin_file(&host
->shost_dev
.kobj
, &arcmsr_sysfs_message_read_attr
);
227 printk(KERN_ERR
"arcmsr: alloc sysfs mu_read failed\n");
228 goto error_bin_file_message_read
;
230 error
= sysfs_create_bin_file(&host
->shost_dev
.kobj
, &arcmsr_sysfs_message_write_attr
);
232 printk(KERN_ERR
"arcmsr: alloc sysfs mu_write failed\n");
233 goto error_bin_file_message_write
;
235 error
= sysfs_create_bin_file(&host
->shost_dev
.kobj
, &arcmsr_sysfs_message_clear_attr
);
237 printk(KERN_ERR
"arcmsr: alloc sysfs mu_clear failed\n");
238 goto error_bin_file_message_clear
;
241 error_bin_file_message_clear
:
242 sysfs_remove_bin_file(&host
->shost_dev
.kobj
, &arcmsr_sysfs_message_write_attr
);
243 error_bin_file_message_write
:
244 sysfs_remove_bin_file(&host
->shost_dev
.kobj
, &arcmsr_sysfs_message_read_attr
);
245 error_bin_file_message_read
:
249 void arcmsr_free_sysfs_attr(struct AdapterControlBlock
*acb
)
251 struct Scsi_Host
*host
= acb
->host
;
253 sysfs_remove_bin_file(&host
->shost_dev
.kobj
, &arcmsr_sysfs_message_clear_attr
);
254 sysfs_remove_bin_file(&host
->shost_dev
.kobj
, &arcmsr_sysfs_message_write_attr
);
255 sysfs_remove_bin_file(&host
->shost_dev
.kobj
, &arcmsr_sysfs_message_read_attr
);
260 arcmsr_attr_host_driver_version(struct device
*dev
,
261 struct device_attribute
*attr
, char *buf
)
263 return snprintf(buf
, PAGE_SIZE
,
265 ARCMSR_DRIVER_VERSION
);
269 arcmsr_attr_host_driver_posted_cmd(struct device
*dev
,
270 struct device_attribute
*attr
, char *buf
)
272 struct Scsi_Host
*host
= class_to_shost(dev
);
273 struct AdapterControlBlock
*acb
=
274 (struct AdapterControlBlock
*) host
->hostdata
;
275 return snprintf(buf
, PAGE_SIZE
,
277 atomic_read(&acb
->ccboutstandingcount
));
281 arcmsr_attr_host_driver_reset(struct device
*dev
,
282 struct device_attribute
*attr
, char *buf
)
284 struct Scsi_Host
*host
= class_to_shost(dev
);
285 struct AdapterControlBlock
*acb
=
286 (struct AdapterControlBlock
*) host
->hostdata
;
287 return snprintf(buf
, PAGE_SIZE
,
293 arcmsr_attr_host_driver_abort(struct device
*dev
,
294 struct device_attribute
*attr
, char *buf
)
296 struct Scsi_Host
*host
= class_to_shost(dev
);
297 struct AdapterControlBlock
*acb
=
298 (struct AdapterControlBlock
*) host
->hostdata
;
299 return snprintf(buf
, PAGE_SIZE
,
305 arcmsr_attr_host_fw_model(struct device
*dev
, struct device_attribute
*attr
,
308 struct Scsi_Host
*host
= class_to_shost(dev
);
309 struct AdapterControlBlock
*acb
=
310 (struct AdapterControlBlock
*) host
->hostdata
;
311 return snprintf(buf
, PAGE_SIZE
,
317 arcmsr_attr_host_fw_version(struct device
*dev
,
318 struct device_attribute
*attr
, char *buf
)
320 struct Scsi_Host
*host
= class_to_shost(dev
);
321 struct AdapterControlBlock
*acb
=
322 (struct AdapterControlBlock
*) host
->hostdata
;
324 return snprintf(buf
, PAGE_SIZE
,
330 arcmsr_attr_host_fw_request_len(struct device
*dev
,
331 struct device_attribute
*attr
, char *buf
)
333 struct Scsi_Host
*host
= class_to_shost(dev
);
334 struct AdapterControlBlock
*acb
=
335 (struct AdapterControlBlock
*) host
->hostdata
;
337 return snprintf(buf
, PAGE_SIZE
,
339 acb
->firm_request_len
);
343 arcmsr_attr_host_fw_numbers_queue(struct device
*dev
,
344 struct device_attribute
*attr
, char *buf
)
346 struct Scsi_Host
*host
= class_to_shost(dev
);
347 struct AdapterControlBlock
*acb
=
348 (struct AdapterControlBlock
*) host
->hostdata
;
350 return snprintf(buf
, PAGE_SIZE
,
352 acb
->firm_numbers_queue
);
356 arcmsr_attr_host_fw_sdram_size(struct device
*dev
,
357 struct device_attribute
*attr
, char *buf
)
359 struct Scsi_Host
*host
= class_to_shost(dev
);
360 struct AdapterControlBlock
*acb
=
361 (struct AdapterControlBlock
*) host
->hostdata
;
363 return snprintf(buf
, PAGE_SIZE
,
365 acb
->firm_sdram_size
);
369 arcmsr_attr_host_fw_hd_channels(struct device
*dev
,
370 struct device_attribute
*attr
, char *buf
)
372 struct Scsi_Host
*host
= class_to_shost(dev
);
373 struct AdapterControlBlock
*acb
=
374 (struct AdapterControlBlock
*) host
->hostdata
;
376 return snprintf(buf
, PAGE_SIZE
,
378 acb
->firm_hd_channels
);
381 static DEVICE_ATTR(host_driver_version
, S_IRUGO
, arcmsr_attr_host_driver_version
, NULL
);
382 static DEVICE_ATTR(host_driver_posted_cmd
, S_IRUGO
, arcmsr_attr_host_driver_posted_cmd
, NULL
);
383 static DEVICE_ATTR(host_driver_reset
, S_IRUGO
, arcmsr_attr_host_driver_reset
, NULL
);
384 static DEVICE_ATTR(host_driver_abort
, S_IRUGO
, arcmsr_attr_host_driver_abort
, NULL
);
385 static DEVICE_ATTR(host_fw_model
, S_IRUGO
, arcmsr_attr_host_fw_model
, NULL
);
386 static DEVICE_ATTR(host_fw_version
, S_IRUGO
, arcmsr_attr_host_fw_version
, NULL
);
387 static DEVICE_ATTR(host_fw_request_len
, S_IRUGO
, arcmsr_attr_host_fw_request_len
, NULL
);
388 static DEVICE_ATTR(host_fw_numbers_queue
, S_IRUGO
, arcmsr_attr_host_fw_numbers_queue
, NULL
);
389 static DEVICE_ATTR(host_fw_sdram_size
, S_IRUGO
, arcmsr_attr_host_fw_sdram_size
, NULL
);
390 static DEVICE_ATTR(host_fw_hd_channels
, S_IRUGO
, arcmsr_attr_host_fw_hd_channels
, NULL
);
392 struct device_attribute
*arcmsr_host_attrs
[] = {
393 &dev_attr_host_driver_version
,
394 &dev_attr_host_driver_posted_cmd
,
395 &dev_attr_host_driver_reset
,
396 &dev_attr_host_driver_abort
,
397 &dev_attr_host_fw_model
,
398 &dev_attr_host_fw_version
,
399 &dev_attr_host_fw_request_len
,
400 &dev_attr_host_fw_numbers_queue
,
401 &dev_attr_host_fw_sdram_size
,
402 &dev_attr_host_fw_hd_channels
,