Re: [PATCH 11/11] pm80xx : gpio feature support for motherboard controllers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Viswas,

As ioctl interface is not welcome for new feature, that's why we removed
ioctl interface when pm8001 accepted into mainline.

I suggest you use bsg interface for this, see sas_host_smp.c for details.

Regards,
Jack

On 10/22/2013 02:20 PM, Viswas G wrote:
> 
> Signed-off-by: Viswas G <Viswas.G@xxxxxxxx>
> ---
>  drivers/scsi/pm8001/pm8001_ctl.c  |  248
> ++++++++++++++++++++++++++++++++++++-
>  drivers/scsi/pm8001/pm8001_ctl.h  |   55 ++++++++
>  drivers/scsi/pm8001/pm8001_init.c |   37 ++++++
>  drivers/scsi/pm8001/pm8001_sas.h  |   30 +++++
>  drivers/scsi/pm8001/pm80xx_hwi.c  |  106 ++++++++++++++++
>  drivers/scsi/pm8001/pm80xx_hwi.h  |   49 +++++++
>  6 files changed, 524 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/scsi/pm8001/pm8001_ctl.c
> b/drivers/scsi/pm8001/pm8001_ctl.c
> index 247cb1c..3c9ca21 100644
> --- a/drivers/scsi/pm8001/pm8001_ctl.c
> +++ b/drivers/scsi/pm8001/pm8001_ctl.c
> @@ -40,7 +40,8 @@
>  #include <linux/firmware.h>
>  #include <linux/slab.h>
>  #include "pm8001_sas.h"
> -#include "pm8001_ctl.h"
> +
> +int pm8001_major = -1;
> 
>  /* scsi host attributes */
> 
> @@ -759,3 +760,248 @@ struct device_attribute *pm8001_host_attrs[] = {
>         NULL,
>  };
> 
> +/**
> + * pm8001_open - open the configuration file
> + * @inode: inode being opened
> + * @file: file handle attached
> + *
> + * Called when the configuration device is opened. Does the needed
> + * set up on the handle and then returns
> + *
> + */
> +static int pm8001_open(struct inode *inode, struct file *file)
> +{
> +       struct pm8001_hba_info *pm8001_ha;
> +       unsigned minor_number = iminor(inode);
> +       int err = -ENODEV;
> +
> +       list_for_each_entry(pm8001_ha, &hba_list, list) {
> +               if (pm8001_ha->id == minor_number) {
> +                       file->private_data = pm8001_ha;
> +                       err = 0;
> +                       break;
> +               }
> +       }
> +
> +       return err;
> +}
> +
> +/**
> + * pm8001_close - close the configuration file
> + * @inode: inode being opened
> + * @file: file handle attached
> + *
> + * Called when the configuration device is closed. Does the needed
> + * set up on the handle and then returns
> + *
> + */
> +static int pm8001_close(struct inode *inode, struct file *file)
> +{
> +       return 0;
> +}
> +
> +static long pm8001_info_ioctl(struct pm8001_hba_info *pm8001_ha,
> +                             unsigned long arg)
> +{
> +       u32 ret = 0;
> +       struct ioctl_info_buffer info_buf;
> +       union main_cfg_table main_tbl =  pm8001_ha->main_cfg_tbl;
> +
> +       strcpy(info_buf.information.sz_name, DRV_NAME);
> +
> +       info_buf.information.usmajor_revision = DRV_MAJOR;
> +       info_buf.information.usminor_revision = DRV_MINOR;
> +       info_buf.information.usbuild_revision = DRV_BUILD;
> +       if (pm8001_ha->chip_id == chip_8001) {
> +               info_buf.information.maxoutstandingIO =
> +                       main_tbl.pm8001_tbl.max_out_io;
> +               info_buf.information.maxdevices =
> +                       (main_tbl.pm8001_tbl.max_sgl >> 16) & 0xFFFF;
> +       } else {
> +               info_buf.information.maxoutstandingIO =
> +                       main_tbl.pm80xx_tbl.max_out_io;
> +               info_buf.information.maxdevices =
> +                       (main_tbl.pm80xx_tbl.max_sgl >> 16) & 0xFFFF;
> +       }
> +       info_buf.header.return_code = ADPT_IOCTL_CALL_SUCCESS;
> +
> +       if (copy_to_user((void *)arg, (void *)&info_buf,
> +                        sizeof(struct ioctl_info_buffer))) {
> +               ret = ADPT_IOCTL_CALL_FAILED;
> +       }
> +
> +       return ret;
> +}
> +
> +static long pm8001_gpio_ioctl(struct pm8001_hba_info *pm8001_ha,
> +                             unsigned long arg)
> +{
> +       struct gpio_buffer buffer;
> +       struct pm8001_gpio *payload;
> +       struct gpio_ioctl_resp *gpio_resp;
> +       DECLARE_COMPLETION_ONSTACK(completion);
> +       unsigned long timeout;
> +       u32 ret = 0, operation;
> +
> +       mutex_lock(&pm8001_ha->ioctl_mutex);
> +
> +       if (copy_from_user(&buffer, (struct gpio_buffer *)arg,
> +               sizeof(struct gpio_buffer))) {
> +               ret = ADPT_IOCTL_CALL_FAILED;
> +               goto exit;
> +       }
> +
> +       pm8001_ha->ioctl_completion = &completion;
> +       payload = &buffer.gpio_payload;
> +       operation = payload->operation;
> +       ret = PM8001_CHIP_DISP->gpio_req(pm8001_ha, payload);
> +       if (ret != 0) {
> +               ret = ADPT_IOCTL_CALL_FAILED;
> +               goto exit;
> +       }
> +
> +       timeout = (unsigned long)buffer.header.timeout * 1000;
> +
> +       mod_timer(&pm8001_ha->ioctl_timer, jiffies +
> msecs_to_jiffies(timeout));
> +
> +       wait_for_completion(&completion);
> +
> +       if (pm8001_ha->ioctl_timer_expired) {
> +               ret = ADPT_IOCTL_CALL_TIMEOUT;
> +               goto exit;
> +       }
> +       gpio_resp = &pm8001_ha->gpio_resp;
> +
> +       buffer.header.return_code = ADPT_IOCTL_CALL_SUCCESS;
> +
> +       if (operation == GPIO_READ) {
> +               payload->rd_wr_val              = gpio_resp->gpio_rd_val;
> +               payload->input_enable           =
> gpio_resp->gpio_in_enabled;
> +               payload->pinsetup1              = gpio_resp->gpio_pinsetup1;
> +               payload->pinsetup2              = gpio_resp->gpio_pinsetup2;
> +               payload->event_level            =
> gpio_resp->gpio_evt_change;
> +               payload->event_rising_edge      = gpio_resp->gpio_evt_rise;
> +               payload->event_falling_edge     = gpio_resp->gpio_evt_fall;
> +
> +               if (copy_to_user((void *)arg, (void *)&buffer,
> +                                sizeof(struct gpio_buffer))) {
> +                       ret = ADPT_IOCTL_CALL_FAILED;
> +               }
> +       } else {
> +               if (copy_to_user((void *)arg, (void *)&buffer.header,
> +                                sizeof(struct ioctl_header))) {
> +                       ret = ADPT_IOCTL_CALL_FAILED;
> +               }
> +       }
> +exit:
> +       pm8001_ha->ioctl_timer_expired = 0;
> +       mutex_unlock(&pm8001_ha->ioctl_mutex);
> +       return ret;
> +}
> +
> +/**
> + * pm8001_ioctl - pm8001 configuration request
> + * @inode: inode of device
> + * @file: file handle
> + * @cmd: ioctl command code
> + * @arg: argument
> + *
> + * Handles a configuration ioctl.
> + *
> + */
> +static long pm8001_ioctl(struct file *file,
> +                        unsigned int cmd, unsigned long arg)
> +{
> +       u32 ret = -EACCES;
> +       struct pm8001_hba_info *pm8001_ha;
> +       struct ioctl_header header;
> +
> +       pm8001_ha = file->private_data;
> +
> +       switch (cmd) {
> +
> +       case ADPT_IOCTL_GPIO:
> +               ret = pm8001_gpio_ioctl(pm8001_ha, arg);
> +               break;
> +       case ADPT_IOCTL_INFO:
> +               ret = pm8001_info_ioctl(pm8001_ha, arg);
> +               break;
> +       default:
> +               ret = ADPT_IOCTL_CALL_INVALID_CODE;
> +       }
> +       if (ret == 0)
> +               return ret;
> +       header.return_code = ret;
> +       ret = -EACCES;
> +       if (copy_to_user((void *)arg, (void *)&header,
> +                       sizeof(struct ioctl_header))) {
> +               return -EFAULT;
> +       }
> +       PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("IOCTL failed\n"));
> +       return ret;
> +}
> +
> +/**
> + * pm8001_poll - pm8001 poll request function
> + * @file: file handle
> + * @wait: poll table to wait
> + *
> + * Handles a poll request.
> + *
> + */
> +unsigned int pm8001_poll(struct file *file, poll_table *wait)
> +{
> +       struct pm8001_hba_info *pm8001_ha;
> +       unsigned int mask = 0;
> +
> +       pm8001_ha = file->private_data;
> +
> +       poll_wait(file, &pm8001_ha->pollq, wait);
> +
> +       if (pm8001_ha->gpio_event_occured == 1) {
> +               pm8001_ha->gpio_event_occured = 0;
> +               mask |= POLLIN | POLLRDNORM;
> +       }
> +
> +       return mask;
> +}
> +
> +static const struct file_operations pm8001_fops = {
> +       .owner          = THIS_MODULE,
> +       .open           = pm8001_open,
> +       .release        = pm8001_close,
> +       .unlocked_ioctl = pm8001_ioctl,
> +       .poll           = pm8001_poll,
> +};
> +
> +/**
> + * pm8001_setup_chrdev - registers a char device
> + *
> + * Return value
> + *     0 in case of success, otherwise non-zero
> + */
> +int pm8001_setup_chrdev(void)
> +{
> +       pm8001_major = register_chrdev(0, DRV_NAME, &pm8001_fops);
> +       if (pm8001_major < 0) {
> +               pr_warn("pm8001 : unable to register \"%s\" device\n",
> +                               DRV_NAME);
> +               return pm8001_major;
> +       }
> +       return 0;
> +}
> +
> +/**
> + * pm8001_release_chrdev - unregisters per-adapter management interface
> + *
> + * Return value
> + *     none
> + */
> +void pm8001_release_chrdev(void)
> +{
> +       if (pm8001_major > -1) {
> +               unregister_chrdev(pm8001_major, DRV_NAME);
> +               pm8001_major = -1;
> +       }
> +}
> +
> diff --git a/drivers/scsi/pm8001/pm8001_ctl.h
> b/drivers/scsi/pm8001/pm8001_ctl.h
> index d0d43a2..0064dd3 100644
> --- a/drivers/scsi/pm8001/pm8001_ctl.h
> +++ b/drivers/scsi/pm8001/pm8001_ctl.h
> @@ -55,6 +55,61 @@
>  #define FAIL_OUT_MEMORY                 0x000c00
>  #define FLASH_IN_PROGRESS               0x001000
> 
> +#define ADPT_IOCTL_CALL_SUCCESS                0x00
> +#define ADPT_IOCTL_CALL_FAILED         0x01
> +#define ADPT_IOCTL_CALL_INVALID_CODE   0x03
> +#define ADPT_IOCTL_CALL_INVALID_DEVICE 0x04
> +#define ADPT_IOCTL_CALL_TIMEOUT                0x08
> +
> +#define GPIO_READ      0
> +#define GPIO_WRITE     1
> +#define GPIO_PINSETUP  2
> +#define GPIO_EVENTSETUP        3
> +
> +struct ioctl_header {
> +       u32 io_controller_num;
> +       u32 length;
> +       u32 return_code;
> +       u32 timeout;
> +       u32 direction;
> +};
> +
> +struct ioctl_drv_info {
> +       u8      sz_name[64];
> +       u16     usmajor_revision;
> +       u16     usminor_revision;
> +       u16     usbuild_revision;
> +       u16     reserved0;
> +       u32     maxdevices;
> +       u32     maxoutstandingIO;
> +       u32     reserved[16];
> +};
> +
> +struct pm8001_gpio {
> +       u32 operation;
> +       u32 mask;
> +       u32 rd_wr_val;
> +       u32 input_enable;
> +       u32 pinsetup1;
> +       u32 pinsetup2;
> +       u32 event_level;
> +       u32 event_rising_edge;
> +       u32 event_falling_edge;
> +};
> +
> +struct ioctl_info_buffer {
> +       struct ioctl_header     header;
> +       struct ioctl_drv_info   information;
> +};
> +
> +struct gpio_buffer {
> +       struct ioctl_header     header;
> +       struct pm8001_gpio      gpio_payload;
> +};
> +
> +#define ADPT_IOCTL_INFO                _IOR(0, 0, struct
> ioctl_info_buffer *)
> +#define ADPT_IOCTL_GPIO                _IOWR(0, 1, struct  gpio_buffer *)
> +
>  #define IB_OB_READ_TIMES                256
>  #define SYSFS_OFFSET                    1024
>  #define PM80XX_IB_OB_QUEUE_SIZE         (32 * 1024)
> diff --git a/drivers/scsi/pm8001/pm8001_init.c
> b/drivers/scsi/pm8001/pm8001_init.c
> index 662bf13..ba2e659 100644
> --- a/drivers/scsi/pm8001/pm8001_init.c
> +++ b/drivers/scsi/pm8001/pm8001_init.c
> @@ -148,6 +148,8 @@ static void pm8001_free(struct pm8001_hba_info
> *pm8001_ha)
>         if (!pm8001_ha)
>                 return;
> 
> +       del_timer(&pm8001_ha->ioctl_timer);
> +
>         for (i = 0; i < USI_MAX_MEMCNT; i++) {
>                 if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) {
>                         pci_free_consistent(pm8001_ha->pdev,
> @@ -444,6 +446,24 @@ static int pm8001_ioremap(struct pm8001_hba_info
> *pm8001_ha)
>         return 0;
>  }
> 
> +void pm8001_ioctl_timer_callback(unsigned long data)
> +{
> +       struct pm8001_hba_info *pm8001_ha = (struct pm8001_hba_info *)data;
> +
> +       PM8001_FAIL_DBG(pm8001_ha,
> +               pm8001_printk("Timer expired for GPIO response\n"));
> +
> +       spin_lock(&pm8001_ha->ioctl_lock);
> +
> +       if (pm8001_ha->ioctl_completion != NULL) {
> +               pm8001_ha->ioctl_timer_expired = 1;
> +               complete(pm8001_ha->ioctl_completion);
> +               pm8001_ha->ioctl_completion = NULL;
> +       }
> +
> +       spin_unlock(&pm8001_ha->ioctl_lock);
> +}
> +
>  /**
>   * pm8001_pci_alloc - initialize our ha card structure
>   * @pdev: pci device.
> @@ -479,6 +499,15 @@ static struct pm8001_hba_info
> *pm8001_pci_alloc(struct pci_dev *pdev,
>         else
>                 pm8001_ha->iomb_size = IOMB_SIZE_SPC;
> 
> +       mutex_init(&pm8001_ha->ioctl_mutex);
> +       pm8001_ha->ioctl_completion = NULL;
> +       init_waitqueue_head(&pm8001_ha->pollq);
> +       pm8001_ha->gpio_event_occured = 0;
> +       spin_lock_init(&pm8001_ha->ioctl_lock);
> +       setup_timer(&pm8001_ha->ioctl_timer, pm8001_ioctl_timer_callback,
> +                    (unsigned long)pm8001_ha);
> +
> +
>  #ifdef PM8001_USE_TASKLET
>         /**
>         * default tasklet for non msi-x interrupt handler/first msi-x
> @@ -1147,8 +1176,15 @@ static int __init pm8001_init(void)
>         rc = pci_register_driver(&pm8001_pci_driver);
>         if (rc)
>                 goto err_tp;
> +
> +       rc = pm8001_setup_chrdev();
> +       if (rc)
> +               goto err_ctl;
> +
>         return 0;
> 
> +err_ctl:
> +       pci_unregister_driver(&pm8001_pci_driver);
>  err_tp:
>         sas_release_transport(pm8001_stt);
>  err_wq:
> @@ -1162,6 +1198,7 @@ static void __exit pm8001_exit(void)
>         pci_unregister_driver(&pm8001_pci_driver);
>         sas_release_transport(pm8001_stt);
>         destroy_workqueue(pm8001_wq);
> +       pm8001_release_chrdev();
>  }
> 
>  module_init(pm8001_init);
> diff --git a/drivers/scsi/pm8001/pm8001_sas.h
> b/drivers/scsi/pm8001/pm8001_sas.h
> index 9241c04..9171f0a 100644
> --- a/drivers/scsi/pm8001/pm8001_sas.h
> +++ b/drivers/scsi/pm8001/pm8001_sas.h
> @@ -51,14 +51,21 @@
>  #include <linux/pci.h>
>  #include <linux/interrupt.h>
>  #include <linux/workqueue.h>
> +#include <linux/poll.h>
> +#include <linux/poll.h>
> +#include <linux/timer.h>
>  #include <scsi/libsas.h>
>  #include <scsi/scsi_tcq.h>
>  #include <scsi/sas_ata.h>
>  #include <linux/atomic.h>
>  #include "pm8001_defs.h"
> +#include "pm8001_ctl.h"
> 
>  #define DRV_NAME               "pm80xx"
>  #define DRV_VERSION            "0.1.37"
> +#define DRV_MAJOR              1
> +#define DRV_MINOR              0
> +#define DRV_BUILD              15
>  #define PM8001_FAIL_LOGGING    0x01 /* Error message logging */
>  #define PM8001_INIT_LOGGING    0x02 /* driver init logging */
>  #define PM8001_DISC_LOGGING    0x04 /* discovery layer logging */
> @@ -132,6 +139,17 @@ struct pm8001_ioctl_payload {
>         u8      *func_specific;
>  };
> 
> +struct gpio_ioctl_resp {
> +       u32 tag;
> +       u32 gpio_rd_val;
> +       u32 gpio_in_enabled;
> +       u32 gpio_pinsetup1;
> +       u32 gpio_pinsetup2;
> +       u32 gpio_evt_change;
> +       u32 gpio_evt_rise;
> +       u32 gpio_evt_fall;
> +};
> +
>  #define MPI_FATAL_ERROR_TABLE_OFFSET_MASK 0xFFFFFF
>  #define MPI_FATAL_ERROR_TABLE_SIZE(value) ((0xFF000000 & value) >> SHIFT24)
>  #define MPI_FATAL_EDUMP_TABLE_LO_OFFSET            0x00     /* HNFBUFL */
> @@ -229,6 +247,8 @@ struct pm8001_dispatch {
>         int (*sas_diag_execute_req)(struct pm8001_hba_info *pm8001_ha,
>                 u32 state);
>         int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha);
> +       int (*gpio_req)(struct pm8001_hba_info *pm8001_ha,
> +               struct pm8001_gpio *gpio_payload);
>  };
> 
>  struct pm8001_chip_info {
> @@ -527,6 +547,14 @@ struct pm8001_hba_info {
>         u32                     int_vector;
>         const struct firmware   *fw_image;
>         u8                      outq[PM8001_MAX_MSIX_VEC];
> +       struct completion       *ioctl_completion;
> +       struct mutex            ioctl_mutex;
> +       spinlock_t              ioctl_lock;
> +       u32                     gpio_event_occured;
> +       u32                     ioctl_timer_expired;
> +       struct timer_list       ioctl_timer;
> +       struct gpio_ioctl_resp  gpio_resp;
> +       wait_queue_head_t       pollq;
>  };
> 
>  struct pm8001_work {
> @@ -705,5 +733,7 @@ ssize_t pm8001_get_gsm_dump(struct device *cdev,
> u32, char *buf);
>  /* ctl shared API */
>  extern struct device_attribute *pm8001_host_attrs[];
> 
> +int pm8001_setup_chrdev(void);
> +void pm8001_release_chrdev(void);
>  #endif
> 
> diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c
> b/drivers/scsi/pm8001/pm80xx_hwi.c
> index 4ebc79b..5423844 100644
> --- a/drivers/scsi/pm8001/pm80xx_hwi.c
> +++ b/drivers/scsi/pm8001/pm80xx_hwi.c
> @@ -3481,6 +3481,54 @@ static int ssp_coalesced_comp_resp(struct
> pm8001_hba_info *pm8001_ha,
>         return 0;
>  }
> 
> +static int mpi_gpio_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
> +{
> +       int ret;
> +       struct gpio_ioctl_resp *pgpio_resp;
> +       struct gpio_resp *ppayload = (struct gpio_resp *)(piomb + 4);
> +
> +       spin_lock(&pm8001_ha->ioctl_lock);
> +       if (pm8001_ha->ioctl_completion != NULL) {
> +               ret = del_timer(&pm8001_ha->ioctl_timer);
> +               if (ret)
> +                       PM8001_MSG_DBG(pm8001_ha,
> +                               pm8001_printk("The timer was still in
> use.\n"));
> +               pm8001_ha->ioctl_timer_expired = 0;
> +               pgpio_resp = &pm8001_ha->gpio_resp;
> +               pgpio_resp->gpio_rd_val =
> le32_to_cpu(ppayload->gpio_rd_val);
> +               pgpio_resp->gpio_in_enabled =
> +                       le32_to_cpu(ppayload->gpio_in_enabled);
> +               pgpio_resp->gpio_pinsetup1 =
> +                       le32_to_cpu(ppayload->gpio_pinsetup1);
> +               pgpio_resp->gpio_pinsetup2 =
> +                       le32_to_cpu(ppayload->gpio_pinsetup2);
> +               pgpio_resp->gpio_evt_change =
> +                       le32_to_cpu(ppayload->gpio_evt_change);
> +               pgpio_resp->gpio_evt_rise =
> +                       le32_to_cpu(ppayload->gpio_evt_rise);
> +               pgpio_resp->gpio_evt_fall =
> +                       le32_to_cpu(ppayload->gpio_evt_fall);
> +
> +               complete(pm8001_ha->ioctl_completion);
> +               pm8001_ha->ioctl_completion = NULL;
> +       }
> +       spin_unlock(&pm8001_ha->ioctl_lock);
> +       return 0;
> +}
> +
> +static int mpi_gpio_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
> +{
> +
> +       u32 gpio_event = 0;
> +       struct gpio_event *ppayload = (struct gpio_event *)(piomb + 4);
> +       gpio_event = le32_to_cpu(ppayload->gpio_event);
> +       PM8001_MSG_DBG(pm8001_ha,
> +                      pm8001_printk("GPIO event: 0x%X\n", gpio_event));
> +       pm8001_ha->gpio_event_occured = 1;
> +       wake_up_interruptible(&pm8001_ha->pollq);
> +       return 0;
> +}
> +
>  /**
>   * process_one_iomb - process one outbound Queue memory block
>   * @pm8001_ha: our hba card information
> @@ -3567,10 +3615,12 @@ static void process_one_iomb(struct
> pm8001_hba_info *pm8001_ha, void *piomb)
>         case OPC_OUB_GPIO_RESPONSE:
>                 PM8001_MSG_DBG(pm8001_ha,
>                         pm8001_printk("OPC_OUB_GPIO_RESPONSE\n"));
> +               mpi_gpio_resp(pm8001_ha, piomb);
>                 break;
>         case OPC_OUB_GPIO_EVENT:
>                 PM8001_MSG_DBG(pm8001_ha,
>                         pm8001_printk("OPC_OUB_GPIO_EVENT\n"));
> +               mpi_gpio_event(pm8001_ha, piomb);
>                 break;
>         case OPC_OUB_GENERAL_EVENT:
>                 PM8001_MSG_DBG(pm8001_ha,
> @@ -4510,6 +4560,61 @@ static u32 pm80xx_chip_is_our_interupt(struct
> pm8001_hba_info *pm8001_ha)
>  }
> 
>  /**
> + * pm80xx_chip_gpio_req - support for GPIO operation
> + * @pm8001_ha: our hba card information.
> + * @ioctl_payload: the payload for the GPIO operation
> + */
> +
> +int pm80xx_chip_gpio_req(struct pm8001_hba_info *pm8001_ha,
> +                               struct pm8001_gpio *gpio_payload)
> +{
> +       struct gpio_req payload;
> +       struct inbound_queue_table *circularQ;
> +       int ret;
> +       u32 tag;
> +       u32 opc = OPC_INB_GPIO;
> +
> +       if (pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ADAPTEC2)
> +               return ADPT_IOCTL_CALL_INVALID_DEVICE;
> +
> +       ret = pm8001_tag_alloc(pm8001_ha, &tag);
> +       if (ret)
> +               return -1;
> +
> +       memset(&payload, 0, sizeof(payload));
> +       circularQ = &pm8001_ha->inbnd_q_tbl[0];
> +       payload.tag = cpu_to_le32(tag);
> +       switch (gpio_payload->operation) {
> +       case GPIO_READ:
> +               payload.eobid_ge_gs_gr_gw = cpu_to_le32(GPIO_GR_BIT);
> +               break;
> +       case GPIO_WRITE:
> +               payload.eobid_ge_gs_gr_gw = cpu_to_le32(GPIO_GW_BIT);
> +               payload.gpio_wr_msk = cpu_to_le32(gpio_payload->mask);
> +               payload.gpio_wr_val = cpu_to_le32(gpio_payload->rd_wr_val);
> +               break;
> +       case GPIO_PINSETUP:
> +               payload.eobid_ge_gs_gr_gw = cpu_to_le32(GPIO_GS_BIT);
> +               payload.gpio_in_enabled =
> +                       cpu_to_le32(gpio_payload->input_enable);
> +               payload.gpio_pinsetup1 =
> cpu_to_le32(gpio_payload->pinsetup1);
> +               payload.gpio_pinsetup2 =
> cpu_to_le32(gpio_payload->pinsetup2);
> +               break;
> +       case GPIO_EVENTSETUP:
> +               payload.eobid_ge_gs_gr_gw = cpu_to_le32(GPIO_GE_BIT);
> +               payload.gpio_evt_change =
> +                       cpu_to_le32(gpio_payload->event_level);
> +               payload.gpio_evt_rise =
> +                       cpu_to_le32(gpio_payload->event_rising_edge);
> +               payload.gpio_evt_fall =
> +                       cpu_to_le32(gpio_payload->event_falling_edge);
> +               break;
> +       }
> +       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
> +       return ret;
> +}
> +
> +/**
>   * pm8001_chip_isr - PM8001 isr handler.
>   * @pm8001_ha: our hba card information.
>   * @irq: irq number.
> @@ -4589,4 +4694,5 @@ const struct pm8001_dispatch pm8001_80xx_dispatch = {
>         .set_nvmd_req           = pm8001_chip_set_nvmd_req,
>         .fw_flash_update_req    = pm8001_chip_fw_flash_update_req,
>         .set_dev_state_req      = pm8001_chip_set_dev_state_req,
> +       .gpio_req               = pm80xx_chip_gpio_req,
>  };
> diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h
> b/drivers/scsi/pm8001/pm80xx_hwi.h
> index c86816b..671940a 100644
> --- a/drivers/scsi/pm8001/pm80xx_hwi.h
> +++ b/drivers/scsi/pm8001/pm80xx_hwi.h
> @@ -422,6 +422,55 @@ struct hw_event_ack_req {
>  } __attribute__((packed, aligned(4)));
> 
>  /*
> + * brief the data structure of GPIO Commannd
> + * use to control MPI GPIOs (64 bytes)
> + */
> +struct gpio_req {
> +       __le32  tag;
> +       __le32  eobid_ge_gs_gr_gw;
> +       __le32  gpio_wr_msk;
> +       __le32  gpio_wr_val;
> +       __le32  gpio_in_enabled;
> +       __le32  gpio_pinsetup1;
> +       __le32  gpio_pinsetup2;
> +       __le32  gpio_evt_change;
> +       __le32  gpio_evt_rise;
> +       __le32  gpio_evt_fall;
> +       u32     reserved[5];
> +} __attribute__((packed, aligned(4)));
> +
> +#define GPIO_GW_BIT 0x1
> +#define GPIO_GR_BIT 0x2
> +#define GPIO_GS_BIT 0x4
> +#define GPIO_GE_BIT 0x8
> +
> +/*
> + * brief the data structure of GPIO Response
> + * indicates the completion of GPIO command (64 bytes)
> + */
> +struct gpio_resp {
> +       __le32  tag;
> +       u32     reserved[2];
> +       __le32  gpio_rd_val;
> +       __le32  gpio_in_enabled;
> +       __le32  gpio_pinsetup1;
> +       __le32  gpio_pinsetup2;
> +       __le32  gpio_evt_change;
> +       __le32  gpio_evt_rise;
> +       __le32  gpio_evt_fall;
> +       u32     reserved1[5];
> +} __attribute__((packed, aligned(4)));
> +
> +/*
> + * brief the data structure of GPIO Event
> + * indicates the generation of GPIO event (64 bytes)
> + */
> +struct gpio_event {
> +       __le32  gpio_event;
> +       u32     reserved[14];
> +} __attribute__((packed, aligned(4)));
> +
> +/*
>   * brief the data structure of PHY_START Response Command
>   * indicates the completion of PHY_START command (64 bytes)
>   */
> --
> 1.7.1
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux