linux/drivers/scsi/arcmsr/arcmsr_attr.c
<<
>>
Prefs
   1/*
   2*******************************************************************************
   3**        O.S   : Linux
   4**   FILE NAME  : arcmsr_attr.c
   5**        BY    : Erich Chen
   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
  60struct class_device_attribute *arcmsr_host_attrs[];
  61
  62static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj,
  63                                             struct bin_attribute *bin,
  64                                             char *buf, loff_t off,
  65                                             size_t count)
  66{
  67        struct class_device *cdev = container_of(kobj,struct class_device,kobj);
  68        struct Scsi_Host *host = class_to_shost(cdev);
  69        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
  70        uint8_t *pQbuffer,*ptmpQbuffer;
  71        int32_t allxfer_len = 0;
  72
  73        if (!capable(CAP_SYS_ADMIN))
  74                return -EACCES;
  75
  76        /* do message unit read. */
  77        ptmpQbuffer = (uint8_t *)buf;
  78        while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
  79                && (allxfer_len < 1031)) {
  80                pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
  81                memcpy(ptmpQbuffer, pQbuffer, 1);
  82                acb->rqbuf_firstindex++;
  83                acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
  84                ptmpQbuffer++;
  85                allxfer_len++;
  86        }
  87        if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
  88                struct QBUFFER __iomem *prbuffer;
  89                uint8_t __iomem *iop_data;
  90                int32_t iop_len;
  91
  92                acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
  93                prbuffer = arcmsr_get_iop_rqbuffer(acb);
  94                iop_data = prbuffer->data;
  95                iop_len = readl(&prbuffer->data_len);
  96                while (iop_len > 0) {
  97                        acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
  98                        acb->rqbuf_lastindex++;
  99                        acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
 100                        iop_data++;
 101                        iop_len--;
 102                }
 103                arcmsr_iop_message_read(acb);
 104        }
 105        return (allxfer_len);
 106}
 107
 108static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj,
 109                                              struct bin_attribute *bin,
 110                                              char *buf, loff_t off,
 111                                              size_t count)
 112{
 113        struct class_device *cdev = container_of(kobj,struct class_device,kobj);
 114        struct Scsi_Host *host = class_to_shost(cdev);
 115        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 116        int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
 117        uint8_t *pQbuffer, *ptmpuserbuffer;
 118
 119        if (!capable(CAP_SYS_ADMIN))
 120                return -EACCES;
 121        if (count > 1032)
 122                return -EINVAL;
 123        /* do message unit write. */
 124        ptmpuserbuffer = (uint8_t *)buf;
 125        user_len = (int32_t)count;
 126        wqbuf_lastindex = acb->wqbuf_lastindex;
 127        wqbuf_firstindex = acb->wqbuf_firstindex;
 128        if (wqbuf_lastindex != wqbuf_firstindex) {
 129                arcmsr_post_ioctldata2iop(acb);
 130                return 0;       /*need retry*/
 131        } else {
 132                my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
 133                                &(ARCMSR_MAX_QBUFFER - 1);
 134                if (my_empty_len >= user_len) {
 135                        while (user_len > 0) {
 136                                pQbuffer =
 137                                &acb->wqbuffer[acb->wqbuf_lastindex];
 138                                memcpy(pQbuffer, ptmpuserbuffer, 1);
 139                                acb->wqbuf_lastindex++;
 140                                acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
 141                                ptmpuserbuffer++;
 142                                user_len--;
 143                        }
 144                        if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
 145                                acb->acb_flags &=
 146                                        ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
 147                                arcmsr_post_ioctldata2iop(acb);
 148                        }
 149                        return count;
 150                } else {
 151                        return 0;       /*need retry*/
 152                }
 153        }
 154}
 155
 156static ssize_t arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
 157                                              struct bin_attribute *bin,
 158                                              char *buf, loff_t off,
 159                                              size_t count)
 160{
 161        struct class_device *cdev = container_of(kobj,struct class_device,kobj);
 162        struct Scsi_Host *host = class_to_shost(cdev);
 163        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 164        uint8_t *pQbuffer;
 165
 166        if (!capable(CAP_SYS_ADMIN))
 167                return -EACCES;
 168
 169        if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
 170                acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
 171                arcmsr_iop_message_read(acb);
 172        }
 173        acb->acb_flags |=
 174                (ACB_F_MESSAGE_WQBUFFER_CLEARED
 175                | ACB_F_MESSAGE_RQBUFFER_CLEARED
 176                | ACB_F_MESSAGE_WQBUFFER_READED);
 177        acb->rqbuf_firstindex = 0;
 178        acb->rqbuf_lastindex = 0;
 179        acb->wqbuf_firstindex = 0;
 180        acb->wqbuf_lastindex = 0;
 181        pQbuffer = acb->rqbuffer;
 182        memset(pQbuffer, 0, sizeof (struct QBUFFER));
 183        pQbuffer = acb->wqbuffer;
 184        memset(pQbuffer, 0, sizeof (struct QBUFFER));
 185        return 1;
 186}
 187
 188static struct bin_attribute arcmsr_sysfs_message_read_attr = {
 189        .attr = {
 190                .name = "mu_read",
 191                .mode = S_IRUSR ,
 192                .owner = THIS_MODULE,
 193        },
 194        .size = 1032,
 195        .read = arcmsr_sysfs_iop_message_read,
 196};
 197
 198static struct bin_attribute arcmsr_sysfs_message_write_attr = {
 199        .attr = {
 200                .name = "mu_write",
 201                .mode = S_IWUSR,
 202                .owner = THIS_MODULE,
 203        },
 204        .size = 1032,
 205        .write = arcmsr_sysfs_iop_message_write,
 206};
 207
 208static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
 209        .attr = {
 210                .name = "mu_clear",
 211                .mode = S_IWUSR,
 212                .owner = THIS_MODULE,
 213        },
 214        .size = 1,
 215        .write = arcmsr_sysfs_iop_message_clear,
 216};
 217
 218int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb)
 219{
 220        struct Scsi_Host *host = acb->host;
 221        int error;
 222
 223        error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
 224        if (error) {
 225                printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n");
 226                goto error_bin_file_message_read;
 227        }
 228        error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
 229        if (error) {
 230                printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n");
 231                goto error_bin_file_message_write;
 232        }
 233        error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr);
 234        if (error) {
 235                printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n");
 236                goto error_bin_file_message_clear;
 237        }
 238        return 0;
 239error_bin_file_message_clear:
 240        sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
 241error_bin_file_message_write:
 242        sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
 243error_bin_file_message_read:
 244        return error;
 245}
 246
 247void
 248arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb) {
 249        struct Scsi_Host *host = acb->host;
 250
 251        sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr);
 252        sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
 253        sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
 254}
 255
 256
 257static ssize_t
 258arcmsr_attr_host_driver_version(struct class_device *cdev, char *buf) {
 259        return snprintf(buf, PAGE_SIZE,
 260                        "%s\n",
 261                        ARCMSR_DRIVER_VERSION);
 262}
 263
 264static ssize_t
 265arcmsr_attr_host_driver_posted_cmd(struct class_device *cdev, char *buf) {
 266        struct Scsi_Host *host = class_to_shost(cdev);
 267        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 268        return snprintf(buf, PAGE_SIZE,
 269                        "%4d\n",
 270                        atomic_read(&acb->ccboutstandingcount));
 271}
 272
 273static ssize_t
 274arcmsr_attr_host_driver_reset(struct class_device *cdev, char *buf) {
 275        struct Scsi_Host *host = class_to_shost(cdev);
 276        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 277        return snprintf(buf, PAGE_SIZE,
 278                        "%4d\n",
 279                        acb->num_resets);
 280}
 281
 282static ssize_t
 283arcmsr_attr_host_driver_abort(struct class_device *cdev, char *buf) {
 284        struct Scsi_Host *host = class_to_shost(cdev);
 285        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 286        return snprintf(buf, PAGE_SIZE,
 287                        "%4d\n",
 288                        acb->num_aborts);
 289}
 290
 291static ssize_t
 292arcmsr_attr_host_fw_model(struct class_device *cdev, char *buf) {
 293    struct Scsi_Host *host = class_to_shost(cdev);
 294        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 295        return snprintf(buf, PAGE_SIZE,
 296                        "%s\n",
 297                        acb->firm_model);
 298}
 299
 300static ssize_t
 301arcmsr_attr_host_fw_version(struct class_device *cdev, char *buf) {
 302        struct Scsi_Host *host = class_to_shost(cdev);
 303        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 304
 305        return snprintf(buf, PAGE_SIZE,
 306                        "%s\n",
 307                        acb->firm_version);
 308}
 309
 310static ssize_t
 311arcmsr_attr_host_fw_request_len(struct class_device *cdev, char *buf) {
 312        struct Scsi_Host *host = class_to_shost(cdev);
 313        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 314
 315        return snprintf(buf, PAGE_SIZE,
 316                        "%4d\n",
 317                        acb->firm_request_len);
 318}
 319
 320static ssize_t
 321arcmsr_attr_host_fw_numbers_queue(struct class_device *cdev, char *buf) {
 322        struct Scsi_Host *host = class_to_shost(cdev);
 323        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 324
 325        return snprintf(buf, PAGE_SIZE,
 326                        "%4d\n",
 327                        acb->firm_numbers_queue);
 328}
 329
 330static ssize_t
 331arcmsr_attr_host_fw_sdram_size(struct class_device *cdev, char *buf) {
 332        struct Scsi_Host *host = class_to_shost(cdev);
 333        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 334
 335        return snprintf(buf, PAGE_SIZE,
 336                        "%4d\n",
 337                        acb->firm_sdram_size);
 338}
 339
 340static ssize_t
 341arcmsr_attr_host_fw_hd_channels(struct class_device *cdev, char *buf) {
 342        struct Scsi_Host *host = class_to_shost(cdev);
 343        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 344
 345        return snprintf(buf, PAGE_SIZE,
 346                        "%4d\n",
 347                        acb->firm_hd_channels);
 348}
 349
 350static CLASS_DEVICE_ATTR(host_driver_version, S_IRUGO, arcmsr_attr_host_driver_version, NULL);
 351static CLASS_DEVICE_ATTR(host_driver_posted_cmd, S_IRUGO, arcmsr_attr_host_driver_posted_cmd, NULL);
 352static CLASS_DEVICE_ATTR(host_driver_reset, S_IRUGO, arcmsr_attr_host_driver_reset, NULL);
 353static CLASS_DEVICE_ATTR(host_driver_abort, S_IRUGO, arcmsr_attr_host_driver_abort, NULL);
 354static CLASS_DEVICE_ATTR(host_fw_model, S_IRUGO, arcmsr_attr_host_fw_model, NULL);
 355static CLASS_DEVICE_ATTR(host_fw_version, S_IRUGO, arcmsr_attr_host_fw_version, NULL);
 356static CLASS_DEVICE_ATTR(host_fw_request_len, S_IRUGO, arcmsr_attr_host_fw_request_len, NULL);
 357static CLASS_DEVICE_ATTR(host_fw_numbers_queue, S_IRUGO, arcmsr_attr_host_fw_numbers_queue, NULL);
 358static CLASS_DEVICE_ATTR(host_fw_sdram_size, S_IRUGO, arcmsr_attr_host_fw_sdram_size, NULL);
 359static CLASS_DEVICE_ATTR(host_fw_hd_channels, S_IRUGO, arcmsr_attr_host_fw_hd_channels, NULL);
 360
 361struct class_device_attribute *arcmsr_host_attrs[] = {
 362        &class_device_attr_host_driver_version,
 363        &class_device_attr_host_driver_posted_cmd,
 364        &class_device_attr_host_driver_reset,
 365        &class_device_attr_host_driver_abort,
 366        &class_device_attr_host_fw_model,
 367        &class_device_attr_host_fw_version,
 368        &class_device_attr_host_fw_request_len,
 369        &class_device_attr_host_fw_numbers_queue,
 370        &class_device_attr_host_fw_sdram_size,
 371        &class_device_attr_host_fw_hd_channels,
 372        NULL,
 373};
 374
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.