]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/scsi/arcmsr/arcmsr_attr.c
arcmsr: fix ioctl data read/write error for adapter type C
[karo-tx-linux.git] / drivers / scsi / arcmsr / arcmsr_attr.c
1 /*
2 *******************************************************************************
3 **        O.S   : Linux
4 **   FILE NAME  : arcmsr_attr.c
5 **        BY    : Nick Cheng
6 **   Description: attributes exported to sysfs and device host
7 *******************************************************************************
8 ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
9 **
10 **     Web site: www.areca.com.tw
11 **       E-mail: support@areca.com.tw
12 **
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
23 ** are met:
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.
31 **
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 *******************************************************************************
46 */
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
54 #include <scsi/scsi_cmnd.h>
55 #include <scsi/scsi_device.h>
56 #include <scsi/scsi_host.h>
57 #include <scsi/scsi_transport.h>
58 #include "arcmsr.h"
59
60 struct device_attribute *arcmsr_host_attrs[];
61
62 static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp,
63                                              struct kobject *kobj,
64                                              struct bin_attribute *bin,
65                                              char *buf, loff_t off,
66                                              size_t count)
67 {
68         struct device *dev = container_of(kobj,struct device,kobj);
69         struct Scsi_Host *host = class_to_shost(dev);
70         struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
71         uint8_t *pQbuffer,*ptmpQbuffer;
72         int32_t allxfer_len = 0;
73         unsigned long flags;
74
75         if (!capable(CAP_SYS_ADMIN))
76                 return -EACCES;
77
78         /* do message unit read. */
79         ptmpQbuffer = (uint8_t *)buf;
80         spin_lock_irqsave(&acb->rqbuffer_lock, flags);
81         if (acb->rqbuf_firstindex != acb->rqbuf_lastindex) {
82                 pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
83                 if (acb->rqbuf_firstindex > acb->rqbuf_lastindex) {
84                         if ((ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex) >= 1032) {
85                                 memcpy(ptmpQbuffer, pQbuffer, 1032);
86                                 acb->rqbuf_firstindex += 1032;
87                                 acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
88                                 allxfer_len = 1032;
89                         } else {
90                                 if (((ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex)
91                                         + acb->rqbuf_lastindex) > 1032) {
92                                         memcpy(ptmpQbuffer, pQbuffer,
93                                                 ARCMSR_MAX_QBUFFER
94                                                 - acb->rqbuf_firstindex);
95                                         ptmpQbuffer += ARCMSR_MAX_QBUFFER
96                                                 - acb->rqbuf_firstindex;
97                                         memcpy(ptmpQbuffer, acb->rqbuffer, 1032
98                                                 - (ARCMSR_MAX_QBUFFER -
99                                                 acb->rqbuf_firstindex));
100                                         acb->rqbuf_firstindex = 1032 -
101                                                 (ARCMSR_MAX_QBUFFER -
102                                                 acb->rqbuf_firstindex);
103                                         allxfer_len = 1032;
104                                 } else {
105                                         memcpy(ptmpQbuffer, pQbuffer,
106                                                 ARCMSR_MAX_QBUFFER -
107                                                 acb->rqbuf_firstindex);
108                                         ptmpQbuffer += ARCMSR_MAX_QBUFFER -
109                                                 acb->rqbuf_firstindex;
110                                         memcpy(ptmpQbuffer, acb->rqbuffer,
111                                                 acb->rqbuf_lastindex);
112                                         allxfer_len = ARCMSR_MAX_QBUFFER -
113                                                 acb->rqbuf_firstindex +
114                                                 acb->rqbuf_lastindex;
115                                         acb->rqbuf_firstindex =
116                                                 acb->rqbuf_lastindex;
117                                 }
118                         }
119                 } else {
120                         if ((acb->rqbuf_lastindex - acb->rqbuf_firstindex) > 1032) {
121                                 memcpy(ptmpQbuffer, pQbuffer, 1032);
122                                 acb->rqbuf_firstindex += 1032;
123                                 allxfer_len = 1032;
124                         } else {
125                                 memcpy(ptmpQbuffer, pQbuffer, acb->rqbuf_lastindex
126                                         - acb->rqbuf_firstindex);
127                                 allxfer_len = acb->rqbuf_lastindex -
128                                         acb->rqbuf_firstindex;
129                                 acb->rqbuf_firstindex = acb->rqbuf_lastindex;
130                         }
131                 }
132         }
133         if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
134                 struct QBUFFER __iomem *prbuffer;
135                 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
136                 prbuffer = arcmsr_get_iop_rqbuffer(acb);
137                 if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0)
138                         acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
139         }
140         spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
141         return allxfer_len;
142 }
143
144 static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp,
145                                               struct kobject *kobj,
146                                               struct bin_attribute *bin,
147                                               char *buf, loff_t off,
148                                               size_t count)
149 {
150         struct device *dev = container_of(kobj,struct device,kobj);
151         struct Scsi_Host *host = class_to_shost(dev);
152         struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
153         int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
154         uint8_t *pQbuffer, *ptmpuserbuffer;
155         unsigned long flags;
156
157         if (!capable(CAP_SYS_ADMIN))
158                 return -EACCES;
159         if (count > 1032)
160                 return -EINVAL;
161         /* do message unit write. */
162         ptmpuserbuffer = (uint8_t *)buf;
163         user_len = (int32_t)count;
164         spin_lock_irqsave(&acb->wqbuffer_lock, flags);
165         wqbuf_lastindex = acb->wqbuf_lastindex;
166         wqbuf_firstindex = acb->wqbuf_firstindex;
167         if (wqbuf_lastindex != wqbuf_firstindex) {
168                 arcmsr_write_ioctldata2iop(acb);
169                 spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
170                 return 0;       /*need retry*/
171         } else {
172                 my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
173                         &(ARCMSR_MAX_QBUFFER - 1);
174                 if (my_empty_len >= user_len) {
175                         while (user_len > 0) {
176                                 pQbuffer = &acb->wqbuffer[acb->wqbuf_lastindex];
177                                 memcpy(pQbuffer, ptmpuserbuffer, 1);
178                                 acb->wqbuf_lastindex++;
179                                 acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
180                                 ptmpuserbuffer++;
181                                 user_len--;
182                         }
183                         if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
184                                 acb->acb_flags &=
185                                         ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
186                                 arcmsr_write_ioctldata2iop(acb);
187                         }
188                         spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
189                         return count;
190                 } else {
191                         spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
192                         return 0;       /*need retry*/
193                 }
194         }
195 }
196
197 static ssize_t arcmsr_sysfs_iop_message_clear(struct file *filp,
198                                               struct kobject *kobj,
199                                               struct bin_attribute *bin,
200                                               char *buf, loff_t off,
201                                               size_t count)
202 {
203         struct device *dev = container_of(kobj,struct device,kobj);
204         struct Scsi_Host *host = class_to_shost(dev);
205         struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
206         uint8_t *pQbuffer;
207         unsigned long flags;
208
209         if (!capable(CAP_SYS_ADMIN))
210                 return -EACCES;
211
212         arcmsr_clear_iop2drv_rqueue_buffer(acb);
213         acb->acb_flags |=
214                 (ACB_F_MESSAGE_WQBUFFER_CLEARED
215                 | ACB_F_MESSAGE_RQBUFFER_CLEARED
216                 | ACB_F_MESSAGE_WQBUFFER_READED);
217         spin_lock_irqsave(&acb->rqbuffer_lock, flags);
218         acb->rqbuf_firstindex = 0;
219         acb->rqbuf_lastindex = 0;
220         spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
221         spin_lock_irqsave(&acb->wqbuffer_lock, flags);
222         acb->wqbuf_firstindex = 0;
223         acb->wqbuf_lastindex = 0;
224         spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
225         pQbuffer = acb->rqbuffer;
226         memset(pQbuffer, 0, sizeof (struct QBUFFER));
227         pQbuffer = acb->wqbuffer;
228         memset(pQbuffer, 0, sizeof (struct QBUFFER));
229         return 1;
230 }
231
232 static struct bin_attribute arcmsr_sysfs_message_read_attr = {
233         .attr = {
234                 .name = "mu_read",
235                 .mode = S_IRUSR ,
236         },
237         .size = 1032,
238         .read = arcmsr_sysfs_iop_message_read,
239 };
240
241 static struct bin_attribute arcmsr_sysfs_message_write_attr = {
242         .attr = {
243                 .name = "mu_write",
244                 .mode = S_IWUSR,
245         },
246         .size = 1032,
247         .write = arcmsr_sysfs_iop_message_write,
248 };
249
250 static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
251         .attr = {
252                 .name = "mu_clear",
253                 .mode = S_IWUSR,
254         },
255         .size = 1,
256         .write = arcmsr_sysfs_iop_message_clear,
257 };
258
259 int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb)
260 {
261         struct Scsi_Host *host = acb->host;
262         int error;
263
264         error = sysfs_create_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_read_attr);
265         if (error) {
266                 printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n");
267                 goto error_bin_file_message_read;
268         }
269         error = sysfs_create_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_write_attr);
270         if (error) {
271                 printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n");
272                 goto error_bin_file_message_write;
273         }
274         error = sysfs_create_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_clear_attr);
275         if (error) {
276                 printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n");
277                 goto error_bin_file_message_clear;
278         }
279         return 0;
280 error_bin_file_message_clear:
281         sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_write_attr);
282 error_bin_file_message_write:
283         sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_read_attr);
284 error_bin_file_message_read:
285         return error;
286 }
287
288 void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb)
289 {
290         struct Scsi_Host *host = acb->host;
291
292         sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_clear_attr);
293         sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_write_attr);
294         sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_read_attr);
295 }
296
297
298 static ssize_t
299 arcmsr_attr_host_driver_version(struct device *dev,
300                                 struct device_attribute *attr, char *buf)
301 {
302         return snprintf(buf, PAGE_SIZE,
303                         "%s\n",
304                         ARCMSR_DRIVER_VERSION);
305 }
306
307 static ssize_t
308 arcmsr_attr_host_driver_posted_cmd(struct device *dev,
309                                    struct device_attribute *attr, char *buf)
310 {
311         struct Scsi_Host *host = class_to_shost(dev);
312         struct AdapterControlBlock *acb =
313                 (struct AdapterControlBlock *) host->hostdata;
314         return snprintf(buf, PAGE_SIZE,
315                         "%4d\n",
316                         atomic_read(&acb->ccboutstandingcount));
317 }
318
319 static ssize_t
320 arcmsr_attr_host_driver_reset(struct device *dev,
321                               struct device_attribute *attr, char *buf)
322 {
323         struct Scsi_Host *host = class_to_shost(dev);
324         struct AdapterControlBlock *acb =
325                 (struct AdapterControlBlock *) host->hostdata;
326         return snprintf(buf, PAGE_SIZE,
327                         "%4d\n",
328                         acb->num_resets);
329 }
330
331 static ssize_t
332 arcmsr_attr_host_driver_abort(struct device *dev,
333                               struct device_attribute *attr, char *buf)
334 {
335         struct Scsi_Host *host = class_to_shost(dev);
336         struct AdapterControlBlock *acb =
337                 (struct AdapterControlBlock *) host->hostdata;
338         return snprintf(buf, PAGE_SIZE,
339                         "%4d\n",
340                         acb->num_aborts);
341 }
342
343 static ssize_t
344 arcmsr_attr_host_fw_model(struct device *dev, struct device_attribute *attr,
345                           char *buf)
346 {
347         struct Scsi_Host *host = class_to_shost(dev);
348         struct AdapterControlBlock *acb =
349                 (struct AdapterControlBlock *) host->hostdata;
350         return snprintf(buf, PAGE_SIZE,
351                         "%s\n",
352                         acb->firm_model);
353 }
354
355 static ssize_t
356 arcmsr_attr_host_fw_version(struct device *dev,
357                             struct device_attribute *attr, char *buf)
358 {
359         struct Scsi_Host *host = class_to_shost(dev);
360         struct AdapterControlBlock *acb =
361                         (struct AdapterControlBlock *) host->hostdata;
362
363         return snprintf(buf, PAGE_SIZE,
364                         "%s\n",
365                         acb->firm_version);
366 }
367
368 static ssize_t
369 arcmsr_attr_host_fw_request_len(struct device *dev,
370                                 struct device_attribute *attr, char *buf)
371 {
372         struct Scsi_Host *host = class_to_shost(dev);
373         struct AdapterControlBlock *acb =
374                 (struct AdapterControlBlock *) host->hostdata;
375
376         return snprintf(buf, PAGE_SIZE,
377                         "%4d\n",
378                         acb->firm_request_len);
379 }
380
381 static ssize_t
382 arcmsr_attr_host_fw_numbers_queue(struct device *dev,
383                                   struct device_attribute *attr, char *buf)
384 {
385         struct Scsi_Host *host = class_to_shost(dev);
386         struct AdapterControlBlock *acb =
387                 (struct AdapterControlBlock *) host->hostdata;
388
389         return snprintf(buf, PAGE_SIZE,
390                         "%4d\n",
391                         acb->firm_numbers_queue);
392 }
393
394 static ssize_t
395 arcmsr_attr_host_fw_sdram_size(struct device *dev,
396                                struct device_attribute *attr, char *buf)
397 {
398         struct Scsi_Host *host = class_to_shost(dev);
399         struct AdapterControlBlock *acb =
400                 (struct AdapterControlBlock *) host->hostdata;
401
402         return snprintf(buf, PAGE_SIZE,
403                         "%4d\n",
404                         acb->firm_sdram_size);
405 }
406
407 static ssize_t
408 arcmsr_attr_host_fw_hd_channels(struct device *dev,
409                                 struct device_attribute *attr, char *buf)
410 {
411         struct Scsi_Host *host = class_to_shost(dev);
412         struct AdapterControlBlock *acb =
413                 (struct AdapterControlBlock *) host->hostdata;
414
415         return snprintf(buf, PAGE_SIZE,
416                         "%4d\n",
417                         acb->firm_hd_channels);
418 }
419
420 static DEVICE_ATTR(host_driver_version, S_IRUGO, arcmsr_attr_host_driver_version, NULL);
421 static DEVICE_ATTR(host_driver_posted_cmd, S_IRUGO, arcmsr_attr_host_driver_posted_cmd, NULL);
422 static DEVICE_ATTR(host_driver_reset, S_IRUGO, arcmsr_attr_host_driver_reset, NULL);
423 static DEVICE_ATTR(host_driver_abort, S_IRUGO, arcmsr_attr_host_driver_abort, NULL);
424 static DEVICE_ATTR(host_fw_model, S_IRUGO, arcmsr_attr_host_fw_model, NULL);
425 static DEVICE_ATTR(host_fw_version, S_IRUGO, arcmsr_attr_host_fw_version, NULL);
426 static DEVICE_ATTR(host_fw_request_len, S_IRUGO, arcmsr_attr_host_fw_request_len, NULL);
427 static DEVICE_ATTR(host_fw_numbers_queue, S_IRUGO, arcmsr_attr_host_fw_numbers_queue, NULL);
428 static DEVICE_ATTR(host_fw_sdram_size, S_IRUGO, arcmsr_attr_host_fw_sdram_size, NULL);
429 static DEVICE_ATTR(host_fw_hd_channels, S_IRUGO, arcmsr_attr_host_fw_hd_channels, NULL);
430
431 struct device_attribute *arcmsr_host_attrs[] = {
432         &dev_attr_host_driver_version,
433         &dev_attr_host_driver_posted_cmd,
434         &dev_attr_host_driver_reset,
435         &dev_attr_host_driver_abort,
436         &dev_attr_host_fw_model,
437         &dev_attr_host_fw_version,
438         &dev_attr_host_fw_request_len,
439         &dev_attr_host_fw_numbers_queue,
440         &dev_attr_host_fw_sdram_size,
441         &dev_attr_host_fw_hd_channels,
442         NULL,
443 };